| 391 | } |
| 392 | |
| 393 | void olc::rcw::Engine::Render() |
| 394 | { |
| 395 | // Utility lambda to draw to screen and depth buffer |
| 396 | auto DepthDraw = [&](int x, int y, float z, olc::Pixel p) |
| 397 | { |
| 398 | if (z <= pDepthBuffer[y * vScreenSize.x + x]) |
| 399 | { |
| 400 | pge->Draw(x, y, p); |
| 401 | pDepthBuffer[y * vScreenSize.x + x] = z; |
| 402 | } |
| 403 | }; |
| 404 | |
| 405 | |
| 406 | // Clear screen and depth buffer ======================================== |
| 407 | // pge->Clear(olc::BLACK); <- Left to user to decide |
| 408 | for (int i = 0; i < vScreenSize.x * vScreenSize.y; i++) |
| 409 | pDepthBuffer[i] = INFINITY; |
| 410 | |
| 411 | // Draw World =========================================================== |
| 412 | |
| 413 | // For each column on screen... |
| 414 | for (int x = 0; x < vScreenSize.x; x++) |
| 415 | { |
| 416 | // ...create a ray eminating from player position into world... |
| 417 | float fRayAngle = (fCameraHeading - (fFieldOfView / 2.0f)) + (float(x) / vFloatScreenSize.x) * fFieldOfView; |
| 418 | |
| 419 | // ...create unit vector for that ray... |
| 420 | olc::vf2d vRayDirection = { std::cos(fRayAngle), std::sin(fRayAngle) }; |
| 421 | |
| 422 | // ... and cast ray into world, see what it hits (if anything) |
| 423 | sTileHit hit; |
| 424 | |
| 425 | // Assuming it hits nothing, then we draw to the middle of the screen (far far away) |
| 426 | float fRayLength = INFINITY; |
| 427 | |
| 428 | // Otherwise... |
| 429 | if (CastRayDDA(vCameraPos, vRayDirection, hit)) |
| 430 | { |
| 431 | // It has hit something, so extract information to draw column |
| 432 | olc::vf2d vRay = hit.vHitPos - vCameraPos; |
| 433 | |
| 434 | // Length of ray is vital for pseudo-depth, but we'll also cosine correct to remove fisheye |
| 435 | fRayLength = vRay.mag() * std::cos(fRayAngle - fCameraHeading); |
| 436 | } |
| 437 | |
| 438 | // Calculate locations in column that divides ceiling, wall and floor |
| 439 | float fCeiling = (vFloatScreenSize.y / 2.0f) - (vFloatScreenSize.y / fRayLength); |
| 440 | float fFloor = vFloatScreenSize.y - fCeiling; |
| 441 | float fWallHeight = fFloor - fCeiling; |
| 442 | float fFloorHeight = vFloatScreenSize.y - fFloor; |
| 443 | |
| 444 | // Now draw the column from top to bottom |
| 445 | for (int y = 0; y < vScreenSize.y; y++) |
| 446 | { |
| 447 | if (y <= int(fCeiling)) |
| 448 | { |
| 449 | // For floors and ceilings, we don't use the ray, instead we just pseudo-project |
| 450 | // a plane, a la Mode 7. First calculate depth into screen... |