mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-04-10 19:15:14 +00:00
rewrite scroll fog logic
This commit is contained in:
parent
80004b0dad
commit
45741b24d2
|
@ -141,8 +141,10 @@ struct Viewport
|
||||||
float scrollFog; // a transparency value that determines if fog is blended over the bottom 2D layer
|
float scrollFog; // a transparency value that determines if fog is blended over the bottom 2D layer
|
||||||
int x, y; // viewport coordinates (scaled and in OpenGL format)
|
int x, y; // viewport coordinates (scaled and in OpenGL format)
|
||||||
int width, height; // viewport dimensions (scaled for display surface size)
|
int width, height; // viewport dimensions (scaled for display surface size)
|
||||||
int priority;
|
int priority; // priority
|
||||||
float spotFogColor[3]; // spotlight color on fog
|
int select; // viewport select?
|
||||||
|
int number; // viewport number
|
||||||
|
float spotFogColor[3]; // spotlight color on fog
|
||||||
float scrollAtt;
|
float scrollAtt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -97,31 +97,37 @@ void CNew3D::UploadTextures(unsigned level, unsigned x, unsigned y, unsigned wid
|
||||||
|
|
||||||
void CNew3D::DrawScrollFog()
|
void CNew3D::DrawScrollFog()
|
||||||
{
|
{
|
||||||
|
// ths is my best guess at the logic based upon what games are doing
|
||||||
|
//
|
||||||
|
// ocean hunter - every viewport has scroll fog values set. Must start with lowest priority layers as the higher ones sometimes are garbage
|
||||||
|
// scud race - first viewports in priority layer missing scroll values. The latter ones all contain valid scroll values.
|
||||||
|
// daytona - doesn't seem to use scroll fog at all. Will set scroll values for the first viewports, the end ones contain no scroll values
|
||||||
|
// vf3 - first viewport only has it set. But set with highest select value ?? Rest of the viewports in priority layer contain a lower select value
|
||||||
|
// sega bassfishing - first viewport in priority 1 sets scroll value. The rest all contain the wrong value + a higher select value ..
|
||||||
|
|
||||||
// the logic for this is still not quite right
|
// known bug (vf3) - if you complete the game on a stage that has fogging, that fogging gets carried over into the credits. I did a binary diff on the viewport, it's never updated from the previous stage, neither is the data it's pointing at. Either a game or emulation bug.
|
||||||
// the sroll fog value seems to be set with multiple viewports.. currently unknown which one to use
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
|
|
||||||
|
Viewport *vp = nullptr;
|
||||||
|
|
||||||
for (auto &n : m_nodes) {
|
for (auto &n : m_nodes) {
|
||||||
|
|
||||||
if (n.viewport.scrollFog > 0 && n.viewport.priority == i) {
|
|
||||||
|
|
||||||
float rgba[4] = {n.viewport.fogParams[0], n.viewport.fogParams[1], n.viewport.fogParams[2], n.viewport.scrollFog};
|
|
||||||
float attenuation = n.viewport.scrollAtt; // Seems to pass the wrong values!
|
|
||||||
float ambient = n.viewport.fogParams[6];
|
|
||||||
float *spotRGB = n.viewport.spotFogColor;
|
|
||||||
float *spotEllipse = n.viewport.spotEllipse;
|
|
||||||
|
|
||||||
glViewport(0, 0, m_totalXRes, m_totalYRes); // fill the whole viewport
|
|
||||||
m_r3dScrollFog.DrawScrollFog(rgba, attenuation, ambient, spotRGB, spotEllipse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n.viewport.priority == i) {
|
if (n.viewport.priority == i) {
|
||||||
break; // we only want to check the first viewport from each priority level
|
if (!vp || n.viewport.select == vp->select) {
|
||||||
|
vp = &n.viewport; // grab the last viewport with the same select value ??
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vp && vp->scrollFog) {
|
||||||
|
|
||||||
|
float rgba[4] = { vp->fogParams[0], vp->fogParams[1], vp->fogParams[2], vp->scrollFog };
|
||||||
|
|
||||||
|
glViewport(0, 0, m_totalXRes, m_totalYRes); // fill the whole viewport
|
||||||
|
m_r3dScrollFog.DrawScrollFog(rgba, vp->scrollAtt, vp->fogParams[6], vp->spotFogColor, vp->spotEllipse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,8 +709,6 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(vpnode[0] & 0x20)) { // only if viewport enabled
|
if (!(vpnode[0] & 0x20)) { // only if viewport enabled
|
||||||
uint32_t curPri = (vpnode[0x00] >> 3) & 3; // viewport priority
|
|
||||||
uint32_t nodeAddr = vpnode[0x02]; // scene database node pointer
|
|
||||||
|
|
||||||
// create node object
|
// create node object
|
||||||
m_nodes.emplace_back(Node());
|
m_nodes.emplace_back(Node());
|
||||||
|
@ -713,8 +717,11 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
// get pointer to its viewport
|
// get pointer to its viewport
|
||||||
Viewport *vp = &m_nodes.back().viewport;
|
Viewport *vp = &m_nodes.back().viewport;
|
||||||
|
|
||||||
vp->priority = curPri;
|
vp->priority = (vpnode[0] >> 3) & 0x3;
|
||||||
m_currentPriority = curPri;
|
vp->select = (vpnode[0] >> 8) & 0x3;
|
||||||
|
vp->number = (vpnode[0] >> 10);
|
||||||
|
|
||||||
|
m_currentPriority = vp->priority;
|
||||||
|
|
||||||
// Fetch viewport parameters (TO-DO: would rounding make a difference?)
|
// Fetch viewport parameters (TO-DO: would rounding make a difference?)
|
||||||
vp->vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point)
|
vp->vpX = (int)(((vpnode[0x1A] & 0xFFFF) / 16.0f) + 0.5f); // viewport X (12.4 fixed point)
|
||||||
|
@ -724,7 +731,7 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
|
|
||||||
uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address
|
uint32_t matrixBase = vpnode[0x16] & 0xFFFFFF; // matrix base address
|
||||||
|
|
||||||
m_LODBlendTable = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17]);
|
m_LODBlendTable = (LODBlendTable*)TranslateCullingAddress(vpnode[0x17] & 0xFFFFFF);
|
||||||
|
|
||||||
vp->angle_left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]);
|
vp->angle_left = -atan2(*(float *)&vpnode[12], *(float *)&vpnode[13]);
|
||||||
vp->angle_right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
|
vp->angle_right = atan2(*(float *)&vpnode[16], -*(float *)&vpnode[17]);
|
||||||
|
@ -734,7 +741,7 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
// I don't really know what these paramaters are for. They are derived from the view angles somehow.
|
// I don't really know what these paramaters are for. They are derived from the view angles somehow.
|
||||||
// In the sdk it's they are someting like (1/tan(left)-tan(right)) * tan(left)
|
// In the sdk it's they are someting like (1/tan(left)-tan(right)) * tan(left)
|
||||||
// But we know when left=right the value is always 0.5. Any other value and we have off-axis projection
|
// But we know when left=right the value is always 0.5. Any other value and we have off-axis projection
|
||||||
// My theory is, the h/w is using these values set actually set the projection matrix angles
|
// My theory is, the h/w is using these values to actually set the frustum planes angles
|
||||||
// The above vpnode[12], vpnode[13] actually work as a normal vector for the clipping planes (used for culling)
|
// The above vpnode[12], vpnode[13] actually work as a normal vector for the clipping planes (used for culling)
|
||||||
// I think in lost world and dirt devils, there is a missmatch between the computed plane normals, and the view angles
|
// I think in lost world and dirt devils, there is a missmatch between the computed plane normals, and the view angles
|
||||||
if (*(float *)&vpnode[0xa] == 0.5f) {
|
if (*(float *)&vpnode[0xa] == 0.5f) {
|
||||||
|
@ -848,7 +855,7 @@ void CNew3D::RenderViewport(UINT32 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Descend down the node link: Use recursive traversal
|
// Descend down the node link: Use recursive traversal
|
||||||
DescendNodePtr(nodeAddr);
|
DescendNodePtr(vpnode[0x02]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render next viewport
|
// render next viewport
|
||||||
|
|
Loading…
Reference in a new issue