jumpartifact.com_demo_0/src/screen_trunner.cc

660 lines
22 KiB
C++
Raw Normal View History

#include "screen_trunner.h"
// standard library includes
#include <cassert>
#include <cmath>
2023-08-08 02:33:07 +00:00
#include <queue>
#ifndef NDEBUG
#include <iostream>
#endif
// third party includes
2023-08-15 02:53:26 +00:00
#include <raylib.h>
#include <raymath.h>
// local includes
#include "3d_helpers.h"
2023-08-07 03:54:23 +00:00
#include "ems.h"
#include "screen_walker_hack.h"
TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
: Screen(stack),
2023-08-08 02:33:07 +00:00
surface(),
2023-08-10 02:00:03 +00:00
surface_bbs(),
2023-08-18 05:46:33 +00:00
// NOLINTBEGIN(bugprone-integer-division)
2023-08-11 03:38:55 +00:00
walkers{Walker{(float)(SURFACE_UNIT_WIDTH / 4) - SURFACE_X_OFFSET,
(float)(SURFACE_UNIT_HEIGHT / 4) - SURFACE_Y_OFFSET, true},
Walker{(float)((SURFACE_UNIT_WIDTH / 4) * 3) - SURFACE_X_OFFSET,
(float)(SURFACE_UNIT_HEIGHT / 4) - SURFACE_Y_OFFSET, true},
Walker{(float)(SURFACE_UNIT_WIDTH / 4) - SURFACE_X_OFFSET,
(float)((SURFACE_UNIT_HEIGHT / 4) * 3) - SURFACE_Y_OFFSET,
true},
Walker{(float)((SURFACE_UNIT_WIDTH / 4) * 3) - SURFACE_X_OFFSET,
(float)((SURFACE_UNIT_HEIGHT / 4) * 3) - SURFACE_Y_OFFSET,
2023-08-18 05:46:33 +00:00
true}},
// NOLINTEND(bugprone-integer-division)
2023-08-07 03:54:23 +00:00
camera{Vector3{0.0F, 1.0F, 0.5F}, Vector3{0.0F, 0.0F, 0.0F},
Vector3{0.0F, 1.0F, 0.0F}, 80.0F, CAMERA_PERSPECTIVE},
flags(),
2023-08-04 05:32:05 +00:00
TEMP_cube_model(LoadModel("res/test_cube.obj")),
TEMP_cube_texture(LoadTexture("res/test_cube_texture.png")),
TEMP_matrix(get_identity_matrix()),
bgRenderTexture(),
fgRenderTexture(),
2023-08-07 03:54:23 +00:00
camera_pos{0.0F, 4.0F, 4.0F},
camera_target{0.0F, 0.0F, 0.0F},
mouse_hit{0.0F, 0.0F, 0.0F},
2023-08-21 06:11:23 +00:00
surface_triangles(),
electricityEffects(),
idx_hit(SURFACE_UNIT_WIDTH / 2 +
2023-08-15 02:53:26 +00:00
(SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH),
controlled_walker_idx(std::nullopt),
left_text_width(MeasureText("Left", BUTTON_FONT_SIZE)),
right_text_width(MeasureText("Right", BUTTON_FONT_SIZE)),
forward_text_width(MeasureText("Forward", BUTTON_FONT_SIZE)),
reset_surface_text_width(MeasureText("Reset Surface", BUTTON_FONT_SIZE)),
surface_reset_anim_timer(0.0F),
walker_hack_success(false) {
#ifndef NDEBUG
std::cout << "idx_hit initialized to " << idx_hit << std::endl;
#endif
2023-08-04 05:32:05 +00:00
TEMP_cube_model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture =
TEMP_cube_texture;
2023-08-07 03:54:23 +00:00
TEMP_cube_model.transform = TEMP_cube_model.transform *
scale_matrix_xyz(0.5F, 0.5F, 0.5F) *
translate_matrix_y(0.5F);
2023-08-08 02:33:07 +00:00
// Initialize surface.
generate_surface();
2023-08-08 02:33:07 +00:00
// Set up render textures
bgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
2023-08-08 02:33:07 +00:00
#ifndef NDEBUG
std::cout << "Screen finished init.\n";
#endif
2023-08-04 05:32:05 +00:00
}
TRunnerScreen::~TRunnerScreen() {
UnloadRenderTexture(fgRenderTexture);
UnloadRenderTexture(bgRenderTexture);
2023-08-04 05:32:05 +00:00
UnloadTexture(TEMP_cube_texture);
UnloadModel(TEMP_cube_model);
}
bool TRunnerScreen::update(float dt, bool is_resized) {
if (is_resized) {
UnloadRenderTexture(fgRenderTexture);
UnloadRenderTexture(bgRenderTexture);
bgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
fgRenderTexture = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
}
if (flags.test(1)) {
if (walker_hack_success && controlled_walker_idx.has_value()) {
walkers[controlled_walker_idx.value()].set_player_controlled(true);
electricityEffects.push_back(ElectricityEffect(
walkers[controlled_walker_idx.value()].get_body_pos(), 1.7F, 15,
1.0F));
} else {
controlled_walker_idx.reset();
}
flags.reset(1);
}
2023-08-15 02:53:26 +00:00
if (controlled_walker_idx.has_value()) {
auto walker_body_pos =
walkers[controlled_walker_idx.value()].get_body_pos();
camera_target = walker_body_pos + Vector3{0.0F, 1.0F, 0.0F};
float rotation = walkers[controlled_walker_idx.value()].get_rotation();
Vector3 offset = get_rotation_matrix_about_y(rotation + PI) *
Vector3{1.0F, 0.0F, 0.0F} * 4.0F +
Vector3{0.0F, 4.0F, 0.0F};
camera_pos = walkers[controlled_walker_idx.value()].get_body_pos() + offset;
}
if (!flags.test(0)) {
if (controlled_walker_idx.has_value() && IsMouseButtonDown(0)) {
// Check if clicked on button.
if (!walkers[controlled_walker_idx.value()].player_is_turning_left() &&
GetTouchX() >= 0 && GetTouchX() <= left_text_width &&
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
GetTouchY() <= GetScreenHeight()) {
walkers[controlled_walker_idx.value()].player_turn_left();
goto post_check_click;
} else if (!walkers[controlled_walker_idx.value()]
.player_is_turning_right() &&
GetTouchX() >= left_text_width &&
GetTouchX() <= left_text_width + right_text_width &&
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE &&
GetTouchY() <= GetScreenHeight()) {
walkers[controlled_walker_idx.value()].player_turn_right();
goto post_check_click;
} else if (!walkers[controlled_walker_idx.value()]
.player_is_going_forward()) {
if (int width_mid = (left_text_width + right_text_width) / 2 -
forward_text_width / 2;
GetTouchX() >= width_mid &&
GetTouchX() <= width_mid + forward_text_width &&
GetTouchY() >= GetScreenHeight() - BUTTON_FONT_SIZE * 2 &&
GetTouchY() <= GetScreenHeight() - BUTTON_FONT_SIZE) {
walkers[controlled_walker_idx.value()].player_go_forward();
goto post_check_click;
}
}
} else if (IsMouseButtonReleased(0)) {
if (controlled_walker_idx.has_value()) {
walkers[controlled_walker_idx.value()].player_idle();
2023-08-15 06:44:11 +00:00
goto post_check_click;
}
}
2023-08-15 06:48:51 +00:00
if (IsMouseButtonPressed(0)) {
float press_x = GetTouchX();
float press_y = GetTouchY();
// Check if clicked on reset surface.
if (!flags.test(0) &&
press_x >= GetScreenWidth() - reset_surface_text_width &&
press_y <= BUTTON_FONT_SIZE) {
generate_surface_with_triangles();
goto post_check_click;
}
Ray ray = GetMouseRay(Vector2{press_x, press_y}, camera);
#ifndef NDEBUG
std::cout << "X: " << press_x << ", Y: " << press_y << std::endl;
std::cout << "Ray pos: " << ray.position.x << ", " << ray.position.y
<< ", " << ray.position.z << " Ray dir: " << ray.direction.x
<< ", " << ray.direction.y << ", " << ray.direction.z
<< std::endl;
#endif
// Check if clicked on a Walker.
for (unsigned int idx = 0; idx < walkers.size(); ++idx) {
if (GetRayCollisionBox(ray, walkers[idx].get_body_bb()).hit) {
if (controlled_walker_idx.has_value()) {
walkers[controlled_walker_idx.value()].set_player_controlled(false);
}
controlled_walker_idx = idx;
auto s_stack = stack.lock();
if (s_stack) {
s_stack->push_constructing_screen_args<WalkerHackScreen>(
&walker_hack_success);
flags.set(1);
}
// walkers[controlled_walker_idx.value()].set_player_controlled(true);
2023-08-15 02:53:26 +00:00
idx_hit = SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
2023-08-15 02:53:26 +00:00
goto post_check_click;
}
2023-08-15 02:53:26 +00:00
}
// Check if clicked on ground.
for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
++idx) {
int x = idx % SURFACE_UNIT_WIDTH;
int y = idx / SURFACE_UNIT_WIDTH;
float xf = (float)(x)-SURFACE_X_OFFSET;
float zf = (float)(y)-SURFACE_Y_OFFSET;
const auto &current = surface[idx].value();
Vector3 nw{xf - 0.5F, current.nw, zf - 0.5F};
Vector3 ne{xf + 0.5F, current.ne, zf - 0.5F};
Vector3 sw{xf - 0.5F, current.sw, zf + 0.5F};
Vector3 se{xf + 0.5F, current.se, zf + 0.5F};
const auto on_collide_fn = [this, idx, xf, zf,
&current](const auto &collision) {
this->idx_hit = idx;
#ifndef NDEBUG
std::cout << "idx_hit set to " << idx_hit << std::endl;
#endif
this->mouse_hit = collision;
this->camera_target.x = xf;
this->camera_target.y =
(current.nw + current.ne + current.sw + current.se) / 4.0F;
this->camera_target.z = zf;
if (idx != SURFACE_UNIT_WIDTH / 2 +
(SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH) {
this->camera_pos = (Vector3Normalize(this->camera_target) * 4.0F) +
this->camera_target;
this->camera_pos.y += 4.0F;
} else {
this->camera_pos.x = 0.0F;
this->camera_pos.y = this->camera_target.y + 4.0F;
this->camera_pos.z = 0.0F;
}
this->camera_target.y += 1.0F;
if (this->controlled_walker_idx.has_value()) {
this->walkers[this->controlled_walker_idx.value()]
.set_player_controlled(false);
this->controlled_walker_idx = std::nullopt;
}
};
if (GetRayCollisionBox(ray, surface_bbs[idx]).hit) {
if (auto collision = GetRayCollisionTriangle(ray, nw, sw, ne);
collision.hit) {
on_collide_fn(collision.point);
goto post_check_click;
} else if (auto collision = GetRayCollisionTriangle(ray, ne, sw, se);
collision.hit) {
on_collide_fn(collision.point);
goto post_check_click;
}
}
}
}
}
2023-08-15 02:53:26 +00:00
post_check_click:
if (flags.test(0)) {
surface_reset_anim_timer += dt;
if (surface_reset_anim_timer > SURFACE_RESET_TIME) {
flags.reset(0);
surface_triangles.reset();
} else {
for (auto &tri : *surface_triangles) {
tri.update(dt);
}
}
}
camera_to_targets(dt);
2023-08-11 03:38:55 +00:00
for (auto &walker : walkers) {
walker.update(flags.test(0) ? 0.0F : dt, surface_bbs, SURFACE_UNIT_WIDTH,
SURFACE_UNIT_HEIGHT);
2023-08-11 03:38:55 +00:00
}
std::vector<decltype(electricityEffects.size())> to_remove;
for (decltype(electricityEffects.size()) idx = 0;
idx < electricityEffects.size(); ++idx) {
if (electricityEffects[idx].update(dt)) {
to_remove.push_back(idx);
}
}
for (auto iter = to_remove.rbegin(); iter != to_remove.rend(); ++iter) {
if (*iter != electricityEffects.size() - 1) {
electricityEffects[*iter] = *electricityEffects.rbegin();
}
electricityEffects.pop_back();
}
return false;
}
bool TRunnerScreen::draw(RenderTexture *render_texture) {
BeginTextureMode(bgRenderTexture);
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
BeginMode3D(camera);
2023-08-08 02:33:07 +00:00
for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
++idx) {
int x = idx % SURFACE_UNIT_WIDTH;
int y = idx / SURFACE_UNIT_WIDTH;
int ox = x - SURFACE_UNIT_WIDTH / 2;
int oy = y - SURFACE_UNIT_HEIGHT / 2;
float xf = (float)(x)-SURFACE_X_OFFSET;
float zf = (float)(y)-SURFACE_Y_OFFSET;
Color color = idx == idx_hit
? RAYWHITE
: Color{(unsigned char)(200 + ox * 2),
(unsigned char)(150 + oy * 2), 20, 255};
const auto &current = surface[idx].value();
float reset_y_offset = 0.0F;
if (flags.test(0)) {
reset_y_offset = (1.0F - std::sin(surface_reset_anim_timer /
SURFACE_RESET_TIME * PI / 2.0F)) *
-SURFACE_RESET_Y_OFFSET;
}
DrawTriangle3D(Vector3{xf - 0.5F, current.nw + reset_y_offset, zf - 0.5F},
Vector3{xf - 0.5F, current.sw + reset_y_offset, zf + 0.5F},
Vector3{xf + 0.5F, current.ne + reset_y_offset, zf - 0.5F},
color);
DrawTriangle3D(Vector3{xf + 0.5F, current.se + reset_y_offset, zf + 0.5F},
Vector3{xf + 0.5F, current.ne + reset_y_offset, zf - 0.5F},
Vector3{xf - 0.5F, current.sw + reset_y_offset, zf + 0.5F},
color);
2023-08-07 03:54:23 +00:00
}
2023-08-11 03:38:55 +00:00
for (auto &walker : walkers) {
walker.draw(TEMP_cube_model);
}
for (auto &ee : electricityEffects) {
ee.draw(GREEN);
}
// TODO DEBUG
if (!controlled_walker_idx.has_value() && !flags.test(0)) {
2023-08-15 02:53:26 +00:00
DrawLine3D(Vector3{0.0F, 3.0F, 0.0F}, mouse_hit, BLACK);
for (const auto &walker : walkers) {
BoundingBox bb = walker.get_body_bb();
bb.min = bb.min - Vector3{0.001F, 0.001F, 0.001F};
bb.max = bb.max + Vector3{0.001F, 0.001F, 0.001F};
DrawBoundingBox(bb, RED);
}
2023-08-15 02:53:26 +00:00
}
EndMode3D();
2023-08-22 02:53:06 +00:00
if (!flags.test(0)) {
if (!flags.test(1) && controlled_walker_idx.has_value()) {
2023-08-22 02:53:06 +00:00
int total_width = 0;
DrawRectangle(0, GetScreenHeight() - BUTTON_FONT_SIZE, left_text_width,
BUTTON_FONT_SIZE, Color{255, 255, 255, 180});
2023-08-22 02:57:09 +00:00
DrawRectangleLines(0, GetScreenHeight() - BUTTON_FONT_SIZE,
left_text_width, BUTTON_FONT_SIZE, GREEN);
2023-08-22 02:53:06 +00:00
DrawText("Left", 0, GetScreenHeight() - BUTTON_FONT_SIZE,
BUTTON_FONT_SIZE, BLACK);
total_width += left_text_width;
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
right_text_width, BUTTON_FONT_SIZE,
Color{255, 255, 255, 180});
2023-08-22 02:57:09 +00:00
DrawRectangleLines(total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
right_text_width, BUTTON_FONT_SIZE, GREEN);
2023-08-22 02:53:06 +00:00
DrawText("Right", total_width, GetScreenHeight() - BUTTON_FONT_SIZE,
BUTTON_FONT_SIZE, BLACK);
total_width =
(total_width + right_text_width) / 2 - forward_text_width / 2;
DrawRectangle(total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
forward_text_width, BUTTON_FONT_SIZE,
Color{255, 255, 255, 180});
2023-08-22 02:57:09 +00:00
DrawRectangleLines(total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
forward_text_width, BUTTON_FONT_SIZE, GREEN);
2023-08-22 02:53:06 +00:00
DrawText("Forward", total_width, GetScreenHeight() - BUTTON_FONT_SIZE * 2,
BUTTON_FONT_SIZE, BLACK);
}
DrawRectangle(GetScreenWidth() - reset_surface_text_width, 0,
reset_surface_text_width, BUTTON_FONT_SIZE,
Color{255, 255, 255, 180});
2023-08-22 02:57:09 +00:00
DrawRectangleLines(GetScreenWidth() - reset_surface_text_width, 0,
reset_surface_text_width, BUTTON_FONT_SIZE, GREEN);
2023-08-22 02:53:06 +00:00
DrawText("Reset Surface", GetScreenWidth() - reset_surface_text_width, 0,
BUTTON_FONT_SIZE, BLACK);
}
EndTextureMode();
if (flags.test(0)) {
2023-08-22 02:53:06 +00:00
BeginTextureMode(fgRenderTexture);
ClearBackground(Color{0, 0, 0, 0});
BeginMode3D(camera);
for (unsigned int idx = 0; idx < SURFACE_UNIT_WIDTH * SURFACE_UNIT_HEIGHT;
++idx) {
int x = idx % SURFACE_UNIT_WIDTH;
int y = idx / SURFACE_UNIT_WIDTH;
int ox = x - SURFACE_UNIT_WIDTH / 2;
int oy = y - SURFACE_UNIT_HEIGHT / 2;
Color color = idx == idx_hit
? RAYWHITE
: Color{(unsigned char)(200 + ox * 2),
(unsigned char)(150 + oy * 2), 20, 255};
if (surface_reset_anim_timer < SURFACE_RESET_TIME_TRI_DRAW) {
unsigned char alpha =
((1.0F - surface_reset_anim_timer / SURFACE_RESET_TIME_TRI_DRAW) *
255.0F);
surface_triangles->at(x * 2 + y * SURFACE_UNIT_WIDTH * 2)
.draw(Color{color.r, color.g, color.b, alpha});
surface_triangles->at(x * 2 + 1 + y * SURFACE_UNIT_WIDTH * 2)
.draw(Color{color.r, color.g, color.b, alpha});
}
}
EndMode3D();
2023-08-15 02:53:26 +00:00
2023-08-22 02:53:06 +00:00
EndTextureMode();
}
BeginTextureMode(*render_texture);
DrawTextureRec(
bgRenderTexture.texture,
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
{0, 0}, WHITE);
2023-08-22 02:53:06 +00:00
if (flags.test(0)) {
DrawTextureRec(
fgRenderTexture.texture,
Rectangle{0, 0, (float)GetScreenWidth(), (float)-GetScreenHeight()},
{0, 0}, WHITE);
}
EndTextureMode();
return true;
}
Color TRunnerScreen::PixelToColor(Pixel p) {
switch (p) {
case PIXEL_BLANK:
return Color{0, 0, 0, 0};
case PIXEL_BLACK:
return Color{0, 0, 0, 255};
case PIXEL_RED:
return Color{255, 50, 50, 255};
case PIXEL_GREEN:
return Color{50, 255, 50, 255};
case PIXEL_BLUE:
return Color{50, 50, 255, 255};
case PIXEL_YELLOW:
return Color{255, 255, 0, 255};
case PIXEL_CYAN:
return Color{0, 255, 255, 255};
case PIXEL_MAGENTA:
return Color{255, 0, 255, 255};
case PIXEL_ORANGE:
return Color{255, 200, 0, 255};
case PIXEL_BROWN:
return Color{180, 130, 0, 255};
case PIXEL_TURQUOISE:
return Color{0, 255, 200, 255};
case PIXEL_SKY:
return Color{168, 178, 255, 255};
case PIXEL_WHITE:
return Color{255, 255, 255, 255};
default:
assert(!"unreachable");
return Color{0, 0, 0, 255};
}
}
2023-08-07 03:54:23 +00:00
void TRunnerScreen::camera_to_targets(float dt) {
camera.position.x +=
(camera_pos.x - camera.position.x) * CAMERA_UPDATE_RATE * dt;
camera.position.y +=
(camera_pos.y - camera.position.y) * CAMERA_UPDATE_RATE * dt;
camera.position.z +=
(camera_pos.z - camera.position.z) * CAMERA_UPDATE_RATE * dt;
camera.target.x +=
(camera_target.x - camera.target.x) * CAMERA_UPDATE_RATE * dt;
camera.target.y +=
(camera_target.y - camera.target.y) * CAMERA_UPDATE_RATE * dt;
camera.target.z +=
(camera_target.z - camera.target.z) * CAMERA_UPDATE_RATE * dt;
}
void TRunnerScreen::generate_surface() {
for (auto &su : surface) {
su = std::nullopt;
}
#ifndef NDEBUG
std::cout << "Initializing surface...\n";
#endif
std::queue<unsigned int> to_update;
to_update.push(SURFACE_UNIT_WIDTH / 2 +
(SURFACE_UNIT_HEIGHT / 2) * SURFACE_UNIT_WIDTH);
while (!to_update.empty()) {
unsigned int idx = to_update.front();
to_update.pop();
if (surface.at(idx).has_value()) {
continue;
}
SurfaceUnit current{0.0F, 0.0F, 0.0F, 0.0F};
// 0000 0001 - nw set
// 0000 0010 - ne set
// 0000 0100 - sw set
// 0000 1000 - se set
unsigned char flags = 0;
// Check adjacent.
if (idx % SURFACE_UNIT_WIDTH > 0) {
if (surface.at(idx - 1).has_value()) {
if ((flags & 1) == 0) {
current.nw = surface.at(idx - 1).value().ne;
flags |= 1;
}
if ((flags & 4) == 0) {
current.sw = surface.at(idx - 1).value().se;
flags |= 4;
}
} else {
to_update.push(idx - 1);
}
}
if (idx % SURFACE_UNIT_WIDTH < SURFACE_UNIT_WIDTH - 1) {
if (surface.at(idx + 1).has_value()) {
if ((flags & 2) == 0) {
current.ne = surface.at(idx + 1).value().nw;
flags |= 2;
}
if ((flags & 8) == 0) {
current.se = surface.at(idx + 1).value().sw;
flags |= 8;
}
} else {
to_update.push(idx + 1);
}
}
if (idx / SURFACE_UNIT_WIDTH > 0) {
if (surface.at(idx - SURFACE_UNIT_WIDTH).has_value()) {
if ((flags & 1) == 0) {
current.nw = surface.at(idx - SURFACE_UNIT_WIDTH).value().sw;
flags |= 1;
}
if ((flags & 2) == 0) {
current.ne = surface.at(idx - SURFACE_UNIT_WIDTH).value().se;
flags |= 2;
}
} else {
to_update.push(idx - SURFACE_UNIT_WIDTH);
}
}
if (idx / SURFACE_UNIT_WIDTH < SURFACE_UNIT_HEIGHT - 1) {
if (surface.at(idx + SURFACE_UNIT_WIDTH).has_value()) {
if ((flags & 4) == 0) {
current.sw = surface.at(idx + SURFACE_UNIT_WIDTH).value().nw;
flags |= 4;
}
if ((flags & 8) == 0) {
current.se = surface.at(idx + SURFACE_UNIT_WIDTH).value().ne;
flags |= 8;
}
} else {
to_update.push(idx + SURFACE_UNIT_WIDTH);
}
}
// Calculate remaining values.
float avg = 0.0F;
unsigned int count = 0;
if ((flags & 1) != 0) {
avg += current.nw;
++count;
}
if ((flags & 2) != 0) {
avg += current.ne;
++count;
}
if ((flags & 4) != 0) {
avg += current.sw;
++count;
}
if ((flags & 8) != 0) {
avg += current.se;
++count;
}
if (count != 0) {
avg = avg / (float)count;
}
if ((flags & 1) == 0) {
current.nw = avg + call_js_get_random() * SURFACE_HEIGHT_INTERVAL -
SURFACE_HEIGHT_INTERVAL / 2.0F;
}
if ((flags & 2) == 0) {
current.ne = avg + call_js_get_random() * SURFACE_HEIGHT_INTERVAL -
SURFACE_HEIGHT_INTERVAL / 2.0F;
}
if ((flags & 4) == 0) {
current.sw = avg + call_js_get_random() * SURFACE_HEIGHT_INTERVAL -
SURFACE_HEIGHT_INTERVAL / 2.0F;
}
if ((flags & 8) == 0) {
current.se = avg + call_js_get_random() * SURFACE_HEIGHT_INTERVAL -
SURFACE_HEIGHT_INTERVAL / 2.0F;
}
surface.at(idx) = current;
// Calculate bounding boxes.
int x = idx % SURFACE_UNIT_WIDTH;
int y = idx / SURFACE_UNIT_WIDTH;
float xf = (float)(x)-SURFACE_X_OFFSET;
float zf = (float)(y)-SURFACE_Y_OFFSET;
surface_bbs.at(idx).min.x = xf - 0.5F;
surface_bbs.at(idx).min.z = zf - 0.5F;
surface_bbs.at(idx).max.x = xf + 0.5F;
surface_bbs.at(idx).max.z = zf + 0.5F;
surface_bbs.at(idx).min.y = current.nw;
if (current.ne < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.ne;
}
if (current.sw < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.sw;
}
if (current.se < surface_bbs.at(idx).min.y) {
surface_bbs.at(idx).min.y = current.se;
}
surface_bbs.at(idx).max.y = current.nw;
if (current.ne > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.ne;
}
if (current.sw > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.sw;
}
if (current.se > surface_bbs.at(idx).max.y) {
surface_bbs.at(idx).max.y = current.se;
}
}
}
void TRunnerScreen::generate_surface_with_triangles() {
surface_triangles = surface_to_triangles(surface, SURFACE_UNIT_WIDTH);
generate_surface();
surface_reset_anim_timer = 0.0F;
flags.set(0);
}