Skip to content

Commit 184c487

Browse files
committed
OpenGL avatar clothing texture rendering
1 parent ee96753 commit 184c487

6 files changed

Lines changed: 249 additions & 21 deletions

File tree

Sources/Plasma/FeatureLib/pfGLPipeline/plGLDevice.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ bool plGLDevice::InitDevice()
386386
glFrontFace(GL_CCW);
387387
glCullFace(GL_BACK);
388388

389+
if (plGLVersion() >= 46)
390+
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
391+
389392
return true;
390393
}
391394

@@ -418,13 +421,22 @@ void plGLDevice::SetRenderTarget(plRenderTarget* target)
418421
ref = static_cast<plGLRenderTargetRef*>(fPipeline->MakeRenderTargetRef(target));
419422
}
420423

421-
if (ref == nullptr)
424+
if (ref == nullptr) {
422425
/// Set to main screen
423426
glBindFramebuffer(GL_FRAMEBUFFER, 0);
424-
else
427+
428+
if (plGLVersion() >= 46)
429+
glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE);
430+
} else {
425431
/// Set to this target
426432
glBindFramebuffer(GL_FRAMEBUFFER, ref->fFrameBuffer);
427433

434+
// We need to flip the Y axis :(
435+
if (plGLVersion() >= 46)
436+
glClipControl(GL_UPPER_LEFT, GL_ZERO_TO_ONE);
437+
// else... find a way to do this with the projection matrix?
438+
}
439+
428440
SetViewport();
429441
}
430442

Sources/Plasma/FeatureLib/pfGLPipeline/plGLMaterialShaderRef.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ void plGLMaterialShaderRef::ICompile()
380380
char* log = new char[length];
381381
glGetShaderInfoLog(vshader, length, &length, log);
382382
hsStatusMessage(log);
383+
delete[] log;
383384
}
384385
}
385386
}
@@ -403,6 +404,7 @@ void plGLMaterialShaderRef::ICompile()
403404
char* log = new char[length];
404405
glGetShaderInfoLog(fFragShaderRef, length, &length, log);
405406
hsStatusMessage(log);
407+
delete[] log;
406408
}
407409
}
408410
}

Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.cpp

Lines changed: 197 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,12 +1517,41 @@ void plGLPipeline::IDrawPlate(plPlate* plate)
15171517

15181518
struct plAVTexVert
15191519
{
1520-
float fPos[3];
1520+
float fPos[2];
15211521
float fUv[2];
15221522
};
15231523

1524+
static const char* AVATAR_VERTEX_SHADER_STRING = R"(#version 430
1525+
1526+
layout(location = 0) in vec2 aVtxPosition;
1527+
layout(location = 1) in vec2 aVtxUV;
1528+
1529+
out vec2 vVtxUV;
1530+
1531+
void main() {
1532+
vVtxUV = aVtxUV;
1533+
gl_Position = vec4(aVtxPosition, 0.0, 1.0);
1534+
})";
1535+
1536+
static const char* AVATAR_FRAGMENT_SHADER_STRING = R"(#version 430
1537+
precision mediump float;
1538+
1539+
layout(location = 0) uniform sampler2D uTex;
1540+
layout(location = 1) uniform vec4 uColor;
1541+
1542+
in highp vec2 vVtxUV;
1543+
out vec4 fragColor;
1544+
1545+
void main() {
1546+
fragColor = texture(uTex, vVtxUV.xy) * uColor;
1547+
})";
1548+
15241549
void plGLPipeline::IPreprocessAvatarTextures()
15251550
{
1551+
static GLuint sVertShader = 0;
1552+
static GLuint sFragShader = 0;
1553+
static GLuint sProgram = 0;
1554+
15261555
plProfile_Set(AvRTPoolUsed, fClothingOutfits.size());
15271556
plProfile_Set(AvRTPoolCount, fAvRTPool.size());
15281557
plProfile_Set(AvRTPoolRes, fAvRTWidth);
@@ -1534,51 +1563,200 @@ void plGLPipeline::IPreprocessAvatarTextures()
15341563
if (fClothingOutfits.empty())
15351564
return;
15361565

1537-
static float kIdentityMatrix[16] = {
1538-
1.0f, 0.0f, 0.0f, 0.0f,
1539-
0.0f, 1.0f, 0.0f, 0.0f,
1540-
0.0f, 0.0f, 1.0f, 0.0f,
1541-
0.0f, 0.0f, 0.0f, 1.0f
1542-
};
1566+
// Set up the shaders the first time to go through here
1567+
if (!sVertShader) {
1568+
GLuint vshader = glCreateShader(GL_VERTEX_SHADER);
1569+
glShaderSource(vshader, 1, &AVATAR_VERTEX_SHADER_STRING, nullptr);
1570+
glCompileShader(vshader);
1571+
LOG_GL_ERROR_CHECK("Vertex Shader compile failed");
1572+
1573+
sVertShader = vshader;
1574+
}
1575+
1576+
if (!sFragShader) {
1577+
GLuint fshader = glCreateShader(GL_FRAGMENT_SHADER);
1578+
glShaderSource(fshader, 1, &AVATAR_FRAGMENT_SHADER_STRING, nullptr);
1579+
glCompileShader(fshader);
1580+
LOG_GL_ERROR_CHECK("Vertex Shader compile failed");
15431581

1544-
//glUniformMatrix4fv(mRef->uMatrixProj, 1, GL_TRUE, kIdentityMatrix);
1545-
//glUniformMatrix4fv(mRef->uMatrixW2C, 1, GL_TRUE, kIdentityMatrix);
1546-
//glUniformMatrix4fv(mRef->uMatrixC2W, 1, GL_TRUE, kIdentityMatrix);
1547-
//glUniformMatrix4fv(mRef->uMatrixL2W, 1, GL_TRUE, kIdentityMatrix);
1582+
sFragShader = fshader;
1583+
}
1584+
1585+
if (!sProgram) {
1586+
GLuint program = glCreateProgram();
1587+
LOG_GL_ERROR_CHECK("Create Program failed");
1588+
1589+
if (plGLVersion() >= 43) {
1590+
const char* name = "AvatarClothing";
1591+
glObjectLabel(GL_PROGRAM, program, strlen(name), name);
1592+
}
1593+
1594+
glAttachShader(program, sVertShader);
1595+
LOG_GL_ERROR_CHECK("Attach Vertex Shader failed");
1596+
1597+
glAttachShader(program, sFragShader);
1598+
LOG_GL_ERROR_CHECK("Attach Fragment Shader failed");
1599+
1600+
glLinkProgram(program);
1601+
LOG_GL_ERROR_CHECK("Program Link failed");
1602+
1603+
GLint isLinked = 0;
1604+
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
1605+
if (isLinked == GL_FALSE)
1606+
{
1607+
GLint maxLength = 0;
1608+
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
1609+
1610+
// The maxLength includes the NULL character
1611+
char* log = new char[maxLength];
1612+
glGetProgramInfoLog(program, maxLength, &maxLength, log);
1613+
1614+
hsStatusMessage(log);
1615+
delete[] log;
1616+
}
1617+
1618+
sProgram = program;
1619+
}
15481620

15491621
for (size_t oIdx = 0; oIdx < fClothingOutfits.size(); oIdx++) {
15501622
plClothingOutfit* co = fClothingOutfits[oIdx];
15511623
if (co->fBase == nullptr || co->fBase->fBaseTexture == nullptr)
15521624
continue;
15531625

1554-
#if 0
15551626
plRenderTarget* rt = plRenderTarget::ConvertNoRef(co->fTargetLayer->GetTexture());
15561627
if (rt != nullptr && co->fDirtyItems.Empty())
15571628
// we've still got our valid RT from last frame and we have nothing to do.
15581629
continue;
15591630

15601631
if (rt == nullptr) {
15611632
rt = IGetNextAvRT();
1633+
1634+
plGLMaterialShaderRef* mRef = static_cast<plGLMaterialShaderRef*>(co->fMaterial->GetDeviceRef());
1635+
if (mRef)
1636+
mRef->SetDirty(true);
1637+
15621638
co->fTargetLayer->SetTexture(rt);
15631639
}
1564-
#endif
15651640

1566-
//PushRenderTarget(rt);
1641+
PushRenderTarget(rt);
1642+
glViewport(0, 0, rt->GetWidth(), rt->GetHeight());
1643+
glDepthRange(0.0, 1.0);
15671644

1568-
// HACK HACK HACK
1569-
co->fTargetLayer->SetTexture(co->fBase->fBaseTexture);
1645+
glUseProgram(sProgram);
1646+
LOG_GL_ERROR_CHECK("Use Program failed");
1647+
fDevice.fCurrentProgram = sProgram;
1648+
1649+
glUniform1i(0, 0);
1650+
glUniform4f(1, 1.f, 1.f, 1.f, 1.f);
1651+
glDepthFunc(GL_LEQUAL);
1652+
glDepthMask(GL_TRUE);
15701653

1571-
// TODO: Actually render to the render target
1654+
float uOff = 0.5f / rt->GetWidth();
1655+
float vOff = 0.5f / rt->GetHeight();
15721656

1573-
//PopRenderTarget();
1574-
//co->fDirtyItems.Clear();
1657+
IDrawClothingQuad(-1.f, -1.f, 2.f, 2.f, uOff, vOff, co->fBase->fBaseTexture);
1658+
plClothingLayout *layout = plClothingMgr::GetClothingMgr()->GetLayout(co->fBase->fLayoutName);
1659+
1660+
for (plClothingItem *item : co->fItems) {
1661+
for (size_t j = 0; j < item->fElements.size(); j++) {
1662+
for (int k = 0; k < plClothingElement::kLayerMax; k++) {
1663+
if (item->fTextures[j][k] == nullptr)
1664+
continue;
1665+
1666+
plMipmap* itemBufferTex = item->fTextures[j][k];
1667+
hsColorRGBA tint = co->GetItemTint(item, k);
1668+
if (k >= plClothingElement::kLayerSkinBlend1 && k <= plClothingElement::kLayerSkinLast)
1669+
tint.a = co->fSkinBlends[k - plClothingElement::kLayerSkinBlend1];
1670+
1671+
if (k == plClothingElement::kLayerBase) {
1672+
glBlendFunc(GL_ONE, GL_ZERO);
1673+
} else {
1674+
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
1675+
}
1676+
1677+
glUniform4f(1, tint.r, tint.g, tint.b, tint.a);
1678+
1679+
float screenW = (float)item->fElements[j]->fWidth / layout->fOrigWidth * 2.f;
1680+
float screenH = (float)item->fElements[j]->fHeight / layout->fOrigWidth * 2.f;
1681+
float screenX = (float)item->fElements[j]->fXPos / layout->fOrigWidth * 2.f - 1.f;
1682+
float screenY = (1.f - (float)item->fElements[j]->fYPos / layout->fOrigWidth) * 2.f - 1.f - screenH;
1683+
1684+
IDrawClothingQuad(screenX, screenY, screenW, screenH, uOff, vOff, itemBufferTex);
1685+
}
1686+
}
1687+
}
1688+
1689+
PopRenderTarget();
1690+
co->fDirtyItems.Clear();
15751691
}
15761692

15771693
fView.fXformResetFlags = fView.kResetAll;
15781694

15791695
fClothingOutfits.swap(fPrevClothingOutfits);
15801696
}
15811697

1698+
void plGLPipeline::IDrawClothingQuad(float x, float y, float w, float h, float uOff, float vOff, plMipmap *tex)
1699+
{
1700+
const uint32_t kVSize = sizeof(plAVTexVert);
1701+
1702+
plGLTextureRef* ref = static_cast<plGLTextureRef*>(tex->GetDeviceRef());
1703+
if (!ref || ref->IsDirty())
1704+
{
1705+
CheckTextureRef(tex);
1706+
ref = (plGLTextureRef*)tex->GetDeviceRef();
1707+
}
1708+
1709+
glActiveTexture(GL_TEXTURE0);
1710+
LOG_GL_ERROR_CHECK("Active Texture failed")
1711+
1712+
glBindTexture(GL_TEXTURE_2D, ref->fRef);
1713+
LOG_GL_ERROR_CHECK("Bind Texture failed");
1714+
1715+
plAVTexVert ptr[4];
1716+
plAVTexVert vert;
1717+
vert.fPos[0] = x;
1718+
vert.fPos[1] = y;
1719+
vert.fUv[0] = uOff;
1720+
vert.fUv[1] = 1.f + vOff;
1721+
1722+
// P0
1723+
ptr[2] = vert;
1724+
1725+
// P1
1726+
ptr[0] = vert;
1727+
ptr[0].fPos[0] += w;
1728+
ptr[0].fUv[0] += 1.f;
1729+
1730+
// P2
1731+
ptr[1] = vert;
1732+
ptr[1].fPos[0] += w;
1733+
ptr[1].fUv[0] += 1.f;
1734+
ptr[1].fPos[1] += h;
1735+
ptr[1].fUv[1] -= 1.f;
1736+
1737+
// P3
1738+
ptr[3] = vert;
1739+
ptr[3].fPos[1] += h;
1740+
ptr[3].fUv[1] -= 1.f;
1741+
1742+
GLuint vbo;
1743+
glGenBuffers(1, &vbo);
1744+
glBindBuffer(GL_ARRAY_BUFFER, vbo);
1745+
glBufferData(GL_ARRAY_BUFFER, sizeof(ptr), ptr, GL_STATIC_DRAW);
1746+
1747+
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, kVSize, (void*)(sizeof(float) * 0));
1748+
glEnableVertexAttribArray(0);
1749+
1750+
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, kVSize, (void*)(sizeof(float) * 2));
1751+
glEnableVertexAttribArray(1);
1752+
1753+
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
1754+
1755+
LOG_GL_ERROR_CHECK("Render failed")
1756+
1757+
glDeleteBuffers(1, &vbo);
1758+
}
1759+
15821760

15831761
bool plGLPipeline::ISoftwareVertexBlend(plDrawableSpans* drawable, const std::vector<int16_t>& visList)
15841762
{

Sources/Plasma/FeatureLib/pfGLPipeline/plGLPipeline.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ class plGLPipeline : public pl3DPipeline<plGLDevice>
148148
void IScaleLight(plGLMaterialShaderRef* mRef, size_t i, float scale);
149149
void IDrawPlate(plPlate* plate);
150150
void IPreprocessAvatarTextures();
151+
void IDrawClothingQuad(float x, float y, float w, float h, float uOff, float vOff, plMipmap *tex);
151152

152153
/**
153154
* Emulate matrix palette operations in software.

Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class plClothingBase : public hsKeyedObject
163163
class plClothingOutfit : public plSynchedObject
164164
{
165165
friend class plDXPipeline;
166+
friend class plGLPipeline;
166167

167168
public:
168169
plArmatureMod *fAvatar;

Sources/Plasma/PubUtilLib/plPipeline/pl3DPipeline.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ class pl3DPipeline : public plPipeline
316316

317317
void CheckTextureRef(plLayerInterface* lay) override;
318318

319+
void CheckTextureRef(plBitmap* bmp);
320+
319321
void SetDefaultFogEnviron(plFogEnvironment* fog) override {
320322
fView.SetDefaultFog(*fog);
321323
}
@@ -1190,6 +1192,38 @@ void pl3DPipeline<DeviceType>::CheckTextureRef(plLayerInterface* layer)
11901192
}
11911193
}
11921194

1195+
template <class DeviceType>
1196+
void pl3DPipeline<DeviceType>::CheckTextureRef(plBitmap* bitmap)
1197+
{
1198+
typename DeviceType::TextureRef* tRef = static_cast<typename DeviceType::TextureRef*>(bitmap->GetDeviceRef());
1199+
1200+
if (!tRef) {
1201+
tRef = new typename DeviceType::TextureRef();
1202+
fDevice.SetupTextureRef(nullptr, bitmap, tRef);
1203+
}
1204+
1205+
if (!tRef->IsLinked())
1206+
tRef->Link(&fTextureRefList);
1207+
1208+
// Make sure it has all resources created.
1209+
fDevice.CheckTexture(tRef);
1210+
1211+
// If it's dirty, refill it.
1212+
if (tRef->IsDirty()) {
1213+
plMipmap* mip = plMipmap::ConvertNoRef(bitmap);
1214+
if (mip) {
1215+
fDevice.MakeTextureRef(tRef, nullptr, mip);
1216+
return;
1217+
}
1218+
1219+
plCubicEnvironmap* cubic = plCubicEnvironmap::ConvertNoRef(bitmap);
1220+
if (cubic) {
1221+
fDevice.MakeCubicTextureRef(tRef, nullptr, cubic);
1222+
return;
1223+
}
1224+
}
1225+
}
1226+
11931227

11941228
template <class DeviceType>
11951229
void pl3DPipeline<DeviceType>::RegisterLight(plLightInfo* liInfo)

0 commit comments

Comments
 (0)