void GLSoftSpriteRenderer::Add(spades::draw::GLImage *img, spades::Vector3 center, float rad, float ang, Vector4 color) { SPADES_MARK_FUNCTION_DEBUG(); const client::SceneDefinition &def = renderer->GetSceneDef(); Sprite spr; spr.image = img; spr.center = center; spr.radius = rad; spr.angle = ang; if (settings.r_hdr) { // linearize color if (color.x > color.w || color.y > color.w || color.z > color.w) { // emissive material color.x *= color.x; color.y *= color.y; color.z *= color.z; } else { // scattering/absorptive material float rcp = fastRcp(color.w + .01); color.x *= color.x * rcp; color.y *= color.y * rcp; color.z *= color.z * rcp; } } spr.color = color; spr.area = rad * rad * 4.f / std::max(Vector3::Dot(center - def.viewOrigin, def.viewAxis[2]), 0.01f); sprites.push_back(spr); }
void SWModelRenderer::RenderInner(spades::draw::SWModel *model, const client::ModelRenderParam ¶m) { auto& mat = param.matrix; auto origin = mat.GetOrigin(); auto axis1 = mat.GetAxis(0); auto axis2 = mat.GetAxis(1); auto axis3 = mat.GetAxis(2); auto *rawModel = model->GetRawModel(); auto rawModelOrigin = rawModel->GetOrigin(); rawModelOrigin += 0.1f; origin += axis1 * rawModelOrigin.x; origin += axis2 * rawModelOrigin.y; origin += axis3 * rawModelOrigin.z; int w = rawModel->GetWidth(); int h = rawModel->GetHeight(); //int d = rawModel->GetDepth(); // evaluate brightness for each normals uint8_t brights[3*3*3]; { auto lightVec = MakeVector3(0.f, -0.707f, -0.707f); float dot1 = Vector3::Dot(axis1, lightVec) * fastRSqrt(axis1.GetPoweredLength()); float dot2 = Vector3::Dot(axis2, lightVec) * fastRSqrt(axis2.GetPoweredLength()); float dot3 = Vector3::Dot(axis3, lightVec) * fastRSqrt(axis3.GetPoweredLength()); for(int x = 0; x < 3; x++){ float d; int cnt; switch(x){ case 0: d = -dot1; cnt = 1; break; case 1: d = 0.f; cnt = 0; break; case 2: d = dot1; cnt = 1; break; } for(int y = 0; y < 3; y++){ auto d2 = d; auto cnt2 = cnt; switch(y){ case 0: d2 -= dot2; cnt2++; break; case 1: break; case 2: d2 += dot2; cnt2++; break; } for(int z = 0; z < 3; z++) { auto d3 = d; auto cnt3 = cnt2; switch(y){ case 0: d3 -= dot3; cnt3++; break; case 1: break; case 2: d3 += dot3; cnt3++; break; } switch(cnt3){ case 2: d3 *= 0.707f; break; case 3: d3 *= 0.57735f; break; } d3 = 192.f + d3 * 62.f; brights[x + y * 3 + z * 9] = static_cast<uint8_t>(d3); } } } } // compute center coord. for culling { auto center = origin; auto localCenter = model->GetCenter(); center += axis1 * localCenter.x; center += axis2 * localCenter.y; center += axis3 * localCenter.z; float largestAxis = axis1.GetPoweredLength(); largestAxis = std::max(largestAxis, axis2.GetPoweredLength()); largestAxis = std::max(largestAxis, axis3.GetPoweredLength()); if(!r->SphereFrustrumCull(center, model->GetRadius() * sqrtf(largestAxis))) return; } Bitmap *fbmp = r->fb; auto *fb = fbmp->GetPixels(); int fw = fbmp->GetWidth(); int fh = fbmp->GetHeight(); auto *db = r->depthBuffer.data(); Matrix4 viewproj = r->GetProjectionViewMatrix(); Vector4 ndc2scrscale = {fw * 0.5f, -fh * 0.5f, 1.f, 1.f}; //Vector4 ndc2scroff = {fw * 0.5f, fh * 0.5f, 0.f, 0.f}; int ndc2scroffX = fw >> 1; int ndc2scroffY = fh >> 1; // render each points auto tOrigin = viewproj * MakeVector4(origin.x, origin.y, origin.z, 1.f); auto tAxis1 = viewproj * MakeVector4(axis1.x, axis1.y, axis1.z, 0.f); auto tAxis2 = viewproj * MakeVector4(axis2.x, axis2.y, axis2.z, 0.f); auto tAxis3 = viewproj * MakeVector4(axis3.x, axis3.y, axis3.z, 0.f); tOrigin *= ndc2scrscale; tAxis1 *= ndc2scrscale; tAxis2 *= ndc2scrscale; tAxis3 *= ndc2scrscale; float pointDiameter;// = largestAxis * 0.55f * fh * 0.5f; { float largestAxis = tAxis1.GetPoweredLength(); largestAxis = std::max(largestAxis, tAxis2.GetPoweredLength()); largestAxis = std::max(largestAxis, tAxis3.GetPoweredLength()); pointDiameter = sqrtf(largestAxis); } uint32_t customColor; customColor = ToFixed8(param.customColor.z) | (ToFixed8(param.customColor.y) << 8) | (ToFixed8(param.customColor.x) << 16); auto v1 = tOrigin; float zNear = r->sceneDef.zNear; for(int x = 0; x < w; x++) { auto v2 = v1; for(int y = 0; y < h; y++) { auto *mp = &model->renderData [model->renderDataAddr[x + y * w]]; while(*mp != -1) { uint32_t data = *(mp++); uint32_t normal = *(mp++); int z = static_cast<int>(data >> 24); //SPAssert(z < d); SPAssert(z >= 0); auto vv = v2 + tAxis3 * zvals[z]; if(vv.z < zNear) continue; // save Z value (don't divide this by W!) float zval = vv.z; // use vv.z for point radius to be divided by W vv.z = pointDiameter; // perspective division float scl = fastRcp(vv.w); vv *= scl; int ix = static_cast<int>(vv.x) + ndc2scroffX; int iy = static_cast<int>(vv.y) + ndc2scroffY; int idm = static_cast<int>(vv.z + .99f); idm = std::max(1, idm); int minX = ix - (idm >> 1); int minY = iy - (idm >> 1); if(minX >= fw || minY >= fh) continue; int maxX = ix + idm; int maxY = iy + idm; if(maxX <= 0 || maxY <= 0) continue; minX = std::max(minX, 0); minY = std::max(minY, 0); maxX = std::min(maxX, fw); maxY = std::min(maxY, fh); auto *fb2 = fb + (minX + minY * fw); auto *db2 = db + (minX + minY * fw); int w = maxX - minX; uint32_t color = data & 0xffffff; if(color == 0) color = customColor; SPAssert(normal < 27); int bright = brights[normal]; #if ENABLE_SSE2 if(lvl == SWFeatureLevel::SSE2) { auto m = _mm_setr_epi32(color, 0, 0, 0); auto f = _mm_set1_epi16(bright << 8); m = _mm_unpacklo_epi8(m, _mm_setzero_si128()); m = _mm_mulhi_epu16(m, f); m = _mm_packus_epi16(m, m); _mm_store_ss(reinterpret_cast<float*>(&color), _mm_castsi128_ps(m)); }else #endif { uint32_t c1 = color & 0xff00; uint32_t c2 = color & 0xff00ff; c1 *= bright; c2 *= bright; color = ((c1&0xff0000) | (c2&0xff00ff00)) >> 8; } for(int yy = minY; yy < maxY; yy++){ auto *fb3 = fb2; auto *db3 = db2; for(int xx = w; xx > 0; xx--) { if(zval < *db3) { *db3 = zval; *fb3 = color; } fb3++; db3++; } fb2 += fw; db2 += fw; } } v2 += tAxis2; } v1 += tAxis1; } }