1 /* 2 Copyright (c) 2013 yvt 3 4 This file is part of OpenSpades. 5 6 OpenSpades is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 OpenSpades is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. 18 19 */ 20 21 #include "SWModelRenderer.h" 22 #include "SWModel.h" 23 #include "SWRenderer.h" 24 #include "SWUtils.h" 25 #include <Core/Bitmap.h> 26 #include <Core/Debug.h> 27 #include <Core/Math.h> 28 29 namespace spades { 30 namespace draw { SWModelRenderer(SWRenderer * r,SWFeatureLevel level)31 SWModelRenderer::SWModelRenderer(SWRenderer *r, SWFeatureLevel level) 32 : r(r), level(level) {} 33 ~SWModelRenderer()34 SWModelRenderer::~SWModelRenderer() {} 35 36 struct ZVals { 37 float zv[512]; ZValsspades::draw::ZVals38 ZVals() { 39 for (int i = 0; i < 512; i++) 40 zv[i] = static_cast<float>(i); 41 } operator []spades::draw::ZVals42 inline float operator[](size_t idx) const { return zv[idx]; } 43 }; 44 static ZVals zvals; 45 46 template <SWFeatureLevel lvl> RenderInner(spades::draw::SWModel * model,const client::ModelRenderParam & param)47 void SWModelRenderer::RenderInner(spades::draw::SWModel *model, 48 const client::ModelRenderParam ¶m) { 49 auto &mat = param.matrix; 50 auto origin = mat.GetOrigin(); 51 auto axis1 = mat.GetAxis(0); 52 auto axis2 = mat.GetAxis(1); 53 auto axis3 = mat.GetAxis(2); 54 auto *rawModel = model->GetRawModel(); 55 auto rawModelOrigin = rawModel->GetOrigin(); 56 rawModelOrigin += 0.25f; 57 origin += axis1 * rawModelOrigin.x; 58 origin += axis2 * rawModelOrigin.y; 59 origin += axis3 * rawModelOrigin.z; 60 61 int w = rawModel->GetWidth(); 62 int h = rawModel->GetHeight(); 63 // int d = rawModel->GetDepth(); 64 65 // evaluate brightness for each normals 66 uint8_t brights[3 * 3 * 3]; 67 { 68 auto lightVec = MakeVector3(0.f, -0.707f, -0.707f); 69 float dot1 = Vector3::Dot(axis1, lightVec) * fastRSqrt(axis1.GetPoweredLength()); 70 float dot2 = Vector3::Dot(axis2, lightVec) * fastRSqrt(axis2.GetPoweredLength()); 71 float dot3 = Vector3::Dot(axis3, lightVec) * fastRSqrt(axis3.GetPoweredLength()); 72 for (int x = 0; x < 3; x++) { 73 float d = 0.0; 74 int cnt = 0; 75 switch (x) { 76 case 0: 77 d = -dot1; 78 cnt = 1; 79 break; 80 case 1: 81 d = 0.f; 82 cnt = 0; 83 break; 84 case 2: 85 d = dot1; 86 cnt = 1; 87 break; 88 } 89 for (int y = 0; y < 3; y++) { 90 auto d2 = d; 91 auto cnt2 = cnt; 92 switch (y) { 93 case 0: 94 d2 -= dot2; 95 cnt2++; 96 break; 97 case 1: break; 98 case 2: 99 d2 += dot2; 100 cnt2++; 101 break; 102 } 103 for (int z = 0; z < 3; z++) { 104 auto d3 = d; 105 auto cnt3 = cnt2; 106 switch (y) { 107 case 0: 108 d3 -= dot3; 109 cnt3++; 110 break; 111 case 1: break; 112 case 2: 113 d3 += dot3; 114 cnt3++; 115 break; 116 } 117 switch (cnt3) { 118 case 2: d3 *= 0.707f; break; 119 case 3: d3 *= 0.57735f; break; 120 } 121 d3 = 192.f + d3 * 62.f; 122 brights[x + y * 3 + z * 9] = static_cast<uint8_t>(d3); 123 } 124 } 125 } 126 } 127 128 // compute center coord. for culling 129 { 130 auto center = origin; 131 auto localCenter = model->GetCenter(); 132 center += axis1 * localCenter.x; 133 center += axis2 * localCenter.y; 134 center += axis3 * localCenter.z; 135 136 float largestAxis = axis1.GetPoweredLength(); 137 largestAxis = std::max(largestAxis, axis2.GetPoweredLength()); 138 largestAxis = std::max(largestAxis, axis3.GetPoweredLength()); 139 140 if (!r->SphereFrustrumCull(center, model->GetRadius() * sqrtf(largestAxis))) 141 return; 142 } 143 144 Bitmap *fbmp = r->fb; 145 auto *fb = fbmp->GetPixels(); 146 int fw = fbmp->GetWidth(); 147 int fh = fbmp->GetHeight(); 148 auto *db = r->depthBuffer.data(); 149 150 Matrix4 viewproj = r->GetProjectionViewMatrix(); 151 Vector4 ndc2scrscale = {fw * 0.5f, -fh * 0.5f, 1.f, 1.f}; 152 // Vector4 ndc2scroff = {fw * 0.5f, fh * 0.5f, 0.f, 0.f}; 153 int ndc2scroffX = fw >> 1; 154 int ndc2scroffY = fh >> 1; 155 156 // render each points 157 auto tOrigin = viewproj * MakeVector4(origin.x, origin.y, origin.z, 1.f); 158 auto tAxis1 = viewproj * MakeVector4(axis1.x, axis1.y, axis1.z, 0.f); 159 auto tAxis2 = viewproj * MakeVector4(axis2.x, axis2.y, axis2.z, 0.f); 160 auto tAxis3 = viewproj * MakeVector4(axis3.x, axis3.y, axis3.z, 0.f); 161 tOrigin *= ndc2scrscale; 162 tAxis1 *= ndc2scrscale; 163 tAxis2 *= ndc2scrscale; 164 tAxis3 *= ndc2scrscale; 165 166 float pointDiameter; // = largestAxis * 0.55f * fh * 0.5f; 167 { 168 float largestAxis = tAxis1.GetPoweredLength(); 169 largestAxis = std::max(largestAxis, tAxis2.GetPoweredLength()); 170 largestAxis = std::max(largestAxis, tAxis3.GetPoweredLength()); 171 pointDiameter = sqrtf(largestAxis); 172 } 173 174 uint32_t customColor; 175 customColor = ToFixed8(param.customColor.z) | (ToFixed8(param.customColor.y) << 8) | 176 (ToFixed8(param.customColor.x) << 16); 177 178 auto v1 = tOrigin; 179 float zNear = r->sceneDef.zNear; 180 for (int x = 0; x < w; x++) { 181 auto v2 = v1; 182 for (int y = 0; y < h; y++) { 183 auto *mp = &model->renderData[model->renderDataAddr[x + y * w]]; 184 while (*mp != -1) { 185 uint32_t data = *(mp++); 186 uint32_t normal = *(mp++); 187 int z = static_cast<int>(data >> 24); 188 // SPAssert(z < d); 189 SPAssert(z >= 0); 190 191 auto vv = v2 + tAxis3 * zvals[z]; 192 if (vv.z < zNear) 193 continue; 194 195 // save Z value (don't divide this by W!) 196 float zval = vv.z; 197 198 // use vv.z for point radius to be divided by W 199 vv.z = pointDiameter; 200 201 // perspective division 202 float scl = fastRcp(vv.w); 203 vv *= scl; 204 205 int ix = static_cast<int>(vv.x) + ndc2scroffX; 206 int iy = static_cast<int>(vv.y) + ndc2scroffY; 207 int idm = static_cast<int>(vv.z + .99f); 208 idm = std::max(1, idm); 209 int minX = ix - (idm >> 1); 210 int minY = iy - (idm >> 1); 211 if (minX >= fw || minY >= fh) 212 continue; 213 int maxX = ix + idm; 214 int maxY = iy + idm; 215 if (maxX <= 0 || maxY <= 0) 216 continue; 217 218 minX = std::max(minX, 0); 219 minY = std::max(minY, 0); 220 maxX = std::min(maxX, fw); 221 maxY = std::min(maxY, fh); 222 223 auto *fb2 = fb + (minX + minY * fw); 224 auto *db2 = db + (minX + minY * fw); 225 int w = maxX - minX; 226 227 uint32_t color = data & 0xffffff; 228 if (color == 0) 229 color = customColor; 230 231 SPAssert(normal < 27); 232 int bright = brights[normal]; 233 #if ENABLE_SSE2 234 if (lvl == SWFeatureLevel::SSE2) { 235 auto m = _mm_setr_epi32(color, 0, 0, 0); 236 auto f = _mm_set1_epi16(bright << 8); 237 238 m = _mm_unpacklo_epi8(m, _mm_setzero_si128()); 239 m = _mm_mulhi_epu16(m, f); 240 m = _mm_packus_epi16(m, m); 241 242 _mm_store_ss(reinterpret_cast<float *>(&color), _mm_castsi128_ps(m)); 243 } else 244 #endif 245 { 246 uint32_t c1 = color & 0xff00; 247 uint32_t c2 = color & 0xff00ff; 248 c1 *= bright; 249 c2 *= bright; 250 color = ((c1 & 0xff0000) | (c2 & 0xff00ff00)) >> 8; 251 } 252 253 for (int yy = minY; yy < maxY; yy++) { 254 auto *fb3 = fb2; 255 auto *db3 = db2; 256 257 for (int xx = w; xx > 0; xx--) { 258 if (zval < *db3) { 259 *db3 = zval; 260 *fb3 = color; 261 } 262 fb3++; 263 db3++; 264 } 265 266 fb2 += fw; 267 db2 += fw; 268 } 269 } 270 v2 += tAxis2; 271 } 272 v1 += tAxis1; 273 } 274 } 275 Render(spades::draw::SWModel * model,const client::ModelRenderParam & param)276 void SWModelRenderer::Render(spades::draw::SWModel *model, 277 const client::ModelRenderParam ¶m) { 278 #if ENABLE_SSE2 279 if (static_cast<int>(level) >= static_cast<int>(SWFeatureLevel::SSE2)) { 280 RenderInner<SWFeatureLevel::SSE2>(model, param); 281 } else 282 #endif 283 RenderInner<SWFeatureLevel::None>(model, param); 284 } 285 } 286 } 287