257 lines
11 KiB
C
257 lines
11 KiB
C
#include "../Engine/Core/engine.h"
|
|
#include "../Engine/Core/logger.h"
|
|
#include "../Engine/Core/timer.h"
|
|
#include "../Engine/Core/asset_manager.h"
|
|
#include "../Engine/Rendering/graphics_device.h"
|
|
#include "../Engine/Rendering/renderer.h"
|
|
#include "../Engine/Rendering/shader.h"
|
|
#include "../Engine/Rendering/mesh.h"
|
|
#include "../Engine/Rendering/material.h"
|
|
#include "../Engine/Rendering/texture.h"
|
|
#include "../Engine/Rendering/camera.h"
|
|
#include "../Engine/Scene/scene_graph.h"
|
|
#include "../Engine/Scene/scene_render.h"
|
|
#include "../Engine/include/engine_api.h"
|
|
#include "../Engine/ASM/math_c_fallback.h"
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <Windows.h>
|
|
|
|
static Scene* g_scene = NULL;
|
|
static AssetManager* g_assets = NULL;
|
|
static Asset* g_shader_asset = NULL;
|
|
static Camera g_camera;
|
|
static int g_mouse_down[3] = {0};
|
|
static int g_last_mx = 0, g_last_my = 0, g_mouse_first = 1;
|
|
|
|
static float player_x = 0, player_z = -8, player_y = 0;
|
|
static float cam_yaw = 0, cam_pitch = 0.3f, cam_dist = 6.0f, cam_height = 3.0f;
|
|
static SceneNode* g_player = NULL;
|
|
static float player_vy = 0;
|
|
static int g_ground = 1;
|
|
|
|
static SceneNode* mknode(Scene* s, SceneNode* p, AssetManager* am, ID3D11Device* dev,
|
|
const char* name, MeshType mt, Vec3 pos, Vec3 scl, Material* mat) {
|
|
SceneNode* n = scene_create_node(s, name);
|
|
if (!n) return NULL;
|
|
if (p) scene_set_parent(n, p);
|
|
n->position = pos; n->scale = scl;
|
|
Asset* ma = asset_manager_load_mesh(am, dev, name);
|
|
if (!ma) {
|
|
const char* b = mt == MESH_CUBE ? "cube" : mt == MESH_SPHERE ? "sphere" : "plane";
|
|
ma = asset_manager_load_mesh(am, dev, b);
|
|
}
|
|
if (ma && mat) {
|
|
MeshRenderer* mr = mesh_renderer_create(mt, (Mesh*)asset_data(ma), mat);
|
|
scene_node_set_mesh_renderer(n, mr);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static Scene* create_world(AssetManager* am, ID3D11Device* dev) {
|
|
Scene* scene = (Scene*)malloc(sizeof(Scene));
|
|
if (!scene) return NULL;
|
|
scene_init(scene);
|
|
SceneNode* root = scene->root;
|
|
root->name[0] = '\0';
|
|
strncpy(root->name, "root", sizeof(root->name) - 1);
|
|
|
|
Shader* sh = (Shader*)asset_data(g_shader_asset);
|
|
|
|
Material* m_green = material_create(sh, NULL); m_green->color = (Vec4){0.25f, 0.55f, 0.2f, 1};
|
|
Material* m_dkgrn = material_create(sh, NULL); m_dkgrn->color = (Vec4){0.15f, 0.4f, 0.12f, 1};
|
|
Material* m_brown = material_create(sh, NULL); m_brown->color = (Vec4){0.45f, 0.28f, 0.15f, 1};
|
|
Material* m_stone = material_create(sh, NULL); m_stone->color = (Vec4){0.5f, 0.5f, 0.5f, 1};
|
|
Material* m_dstone = material_create(sh, NULL); m_dstone->color = (Vec4){0.35f, 0.35f, 0.38f, 1};
|
|
Material* m_red = material_create(sh, NULL); m_red->color = (Vec4){0.8f, 0.2f, 0.15f, 1};
|
|
Material* m_blue = material_create(sh, NULL); m_blue->color = (Vec4){0.2f, 0.4f, 0.8f, 1};
|
|
Material* m_yellow = material_create(sh, NULL); m_yellow->color = (Vec4){0.85f, 0.75f, 0.2f, 1};
|
|
Material* m_white = material_create(sh, NULL); m_white->color = (Vec4){0.85f, 0.85f, 0.85f, 1};
|
|
Material* m_water = material_create(sh, NULL); m_water->color = (Vec4){0.15f, 0.3f, 0.6f, 0.8f};
|
|
Material* m_orange = material_create(sh, NULL); m_orange->color = (Vec4){0.9f, 0.5f, 0.1f, 1};
|
|
Material* m_purple = material_create(sh, NULL); m_purple->color = (Vec4){0.5f, 0.15f, 0.6f, 1};
|
|
Material* m_player = material_create(sh, NULL); m_player->color = (Vec4){0.1f, 0.8f, 0.3f, 1};
|
|
Material* m_path = material_create(sh, NULL); m_path->color = (Vec4){0.6f, 0.55f, 0.45f, 1};
|
|
Material* m_hill = material_create(sh, NULL); m_hill->color = (Vec4){0.2f, 0.4f, 0.18f, 1};
|
|
Material* m_flower = material_create(sh, NULL); m_flower->color = (Vec4){0.9f, 0.2f, 0.4f, 1};
|
|
|
|
mknode(scene, root, am, dev, "ground", MESH_PLANE, (Vec3){0, -0.01f, 0}, (Vec3){40, 1, 40}, m_green);
|
|
|
|
g_player = mknode(scene, root, am, dev, "player", MESH_CUBE, (Vec3){player_x, 0.4f, player_z}, (Vec3){0.3f, 0.8f, 0.3f}, m_player);
|
|
|
|
// 村庄
|
|
mknode(scene, root, am, dev, "house1", MESH_CUBE, (Vec3){-5, 1, -5}, (Vec3){2, 2, 2}, m_red);
|
|
mknode(scene, root, am, dev, "house2", MESH_CUBE, (Vec3){-2, 1.25f, -8}, (Vec3){2.5f, 2.5f, 2}, m_blue);
|
|
mknode(scene, root, am, dev, "house3", MESH_CUBE, (Vec3){1, 0.9f, -6}, (Vec3){1.8f, 1.8f, 1.8f}, m_yellow);
|
|
mknode(scene, root, am, dev, "tower", MESH_CUBE, (Vec3){-7, 1.5f, -2}, (Vec3){1.5f, 3, 1.5f}, m_white);
|
|
mknode(scene, root, am, dev, "house4", MESH_CUBE, (Vec3){4, 1, -4}, (Vec3){2, 2, 2}, m_orange);
|
|
// 屋顶
|
|
mknode(scene, root, am, dev, "roof1", MESH_CUBE, (Vec3){-5, 2.15f, -5}, (Vec3){2.3f, 0.3f, 2.3f}, m_dstone);
|
|
mknode(scene, root, am, dev, "roof2", MESH_CUBE, (Vec3){-2, 2.65f, -8}, (Vec3){2.8f, 0.3f, 2.3f}, m_dstone);
|
|
mknode(scene, root, am, dev, "roof3", MESH_CUBE, (Vec3){1, 2.0f, -6}, (Vec3){2.1f, 0.3f, 2.1f}, m_brown);
|
|
mknode(scene, root, am, dev, "roof4", MESH_CUBE, (Vec3){4, 2.15f, -4}, (Vec3){2.3f, 0.3f, 2.3f}, m_brown);
|
|
|
|
// 树木
|
|
float trees[][2] = {{-12,3},{-10,5},{-8,8},{-6,10},{-3,12},{2,14},{5,10},{8,7},{10,4},{12,2},
|
|
{-14,-1},{-12,-6},{-10,-10},{8,-8},{12,-5},{15,8},{-15,12},{0,18},{-5,15},{10,15},
|
|
{-8,-14},{5,-12},{12,-10},{-14,6},{14,-2},{3,8},{-2,10},{7,12},{-11,8},{9,3}};
|
|
for (int i = 0; i < 30; i++) {
|
|
float x = trees[i][0], z = trees[i][1];
|
|
mknode(scene, root, am, dev, "trunk", MESH_CUBE, (Vec3){x, 0.5f, z}, (Vec3){0.2f, 1, 0.2f}, m_brown);
|
|
mknode(scene, root, am, dev, "leaves", MESH_SPHERE, (Vec3){x, 1.8f, z}, (Vec3){0.8f, 0.7f, 0.8f}, m_dkgrn);
|
|
}
|
|
|
|
// 岩石
|
|
float rocks[][3] = {{6,-2,0.6f},{-9,2,0.4f},{10,10,0.8f},{-6,-12,0.5f},{14,6,0.7f},{-13,-8,0.3f},{3,-10,0.5f},{-4,14,0.4f},{11,-8,0.6f}};
|
|
for (int i = 0; i < 9; i++)
|
|
mknode(scene, root, am, dev, "rock", MESH_SPHERE, (Vec3){rocks[i][0], rocks[i][2]*0.3f, rocks[i][1]}, (Vec3){rocks[i][2], rocks[i][2]*0.6f, rocks[i][2]}, m_stone);
|
|
|
|
// 水塘
|
|
mknode(scene, root, am, dev, "water", MESH_PLANE, (Vec3){-10, 0.02f, -4}, (Vec3){3, 1, 3}, m_water);
|
|
|
|
// 小路
|
|
for (float tz = -10; tz <= 2; tz += 1.5f)
|
|
mknode(scene, root, am, dev, "path", MESH_PLANE, (Vec3){0, 0.01f, tz}, (Vec3){0.6f, 1, 0.4f}, m_path);
|
|
|
|
// 山丘
|
|
mknode(scene, root, am, dev, "hill1", MESH_SPHERE, (Vec3){-18, -0.5f, 15}, (Vec3){8, 3, 8}, m_hill);
|
|
mknode(scene, root, am, dev, "hill2", MESH_SPHERE, (Vec3){20, -0.8f, 12}, (Vec3){10, 4, 10}, m_hill);
|
|
mknode(scene, root, am, dev, "hill3", MESH_SPHERE, (Vec3){0, -0.3f, 22}, (Vec3){12, 3, 8}, m_hill);
|
|
|
|
// 花
|
|
float flowers[][2] = {{-3,-2},{-1,-3},{2,-1},{-4,0},{3,1}};
|
|
for (int i = 0; i < 5; i++)
|
|
mknode(scene, root, am, dev, "flower", MESH_SPHERE, (Vec3){flowers[i][0], 0.15f, flowers[i][1]}, (Vec3){0.1f, 0.1f, 0.1f}, m_flower);
|
|
|
|
scene_update(scene);
|
|
return scene;
|
|
}
|
|
|
|
static void on_render(Engine* engine) {
|
|
Renderer* r = engine_get_renderer(engine);
|
|
GraphicsDevice* dev = engine_get_graphics_device(engine);
|
|
if (!r || !dev || !g_scene) return;
|
|
renderer_set_view(r, camera_get_view(&g_camera));
|
|
renderer_set_projection(r, camera_get_projection(&g_camera));
|
|
renderer_begin_frame(r);
|
|
scene_update(g_scene);
|
|
scene_render(g_scene, r);
|
|
renderer_end_frame(r);
|
|
}
|
|
|
|
static void update_camera(void) {
|
|
g_camera.position = (Vec3){
|
|
player_x - sinf(cam_yaw) * cam_dist,
|
|
cam_height + sinf(cam_pitch) * cam_dist * 0.5f,
|
|
player_z - cosf(cam_yaw) * cam_dist
|
|
};
|
|
g_camera.target = (Vec3){player_x, 0.5f, player_z};
|
|
g_camera.dirty = 1;
|
|
}
|
|
|
|
static void on_update(Engine* engine, double dt) {
|
|
(void)engine;
|
|
float fdt = (float)dt;
|
|
float spd = (GetAsyncKeyState(VK_SHIFT) & 0x8000) ? 10.0f * fdt : 5.0f * fdt;
|
|
float fwd_x = sinf(cam_yaw), fwd_z = cosf(cam_yaw);
|
|
float rgt_x = cosf(cam_yaw), rgt_z = -sinf(cam_yaw);
|
|
if (GetAsyncKeyState('W') & 0x8000) { player_x += fwd_x * spd; player_z += fwd_z * spd; }
|
|
if (GetAsyncKeyState('S') & 0x8000) { player_x -= fwd_x * spd; player_z -= fwd_z * spd; }
|
|
if (GetAsyncKeyState('A') & 0x8000) { player_x -= rgt_x * spd; player_z -= rgt_z * spd; }
|
|
if (GetAsyncKeyState('D') & 0x8000) { player_x += rgt_x * spd; player_z += rgt_z * spd; }
|
|
if (GetAsyncKeyState('Q') & 0x8000) cam_yaw -= 2.0f * fdt;
|
|
if (GetAsyncKeyState('E') & 0x8000) cam_yaw += 2.0f * fdt;
|
|
if ((GetAsyncKeyState(VK_SPACE) & 0x8000) && g_ground) { player_vy = 8.0f; g_ground = 0; }
|
|
player_vy -= 20.0f * fdt;
|
|
player_y += player_vy * fdt;
|
|
if (player_y < 0) { player_y = 0; player_vy = 0; g_ground = 1; }
|
|
if (player_x < -19) player_x = -19; if (player_x > 19) player_x = 19;
|
|
if (player_z < -19) player_z = -19; if (player_z > 21) player_z = 21;
|
|
if (g_player) {
|
|
g_player->position.x = player_x; g_player->position.y = 0.4f + player_y; g_player->position.z = player_z;
|
|
quat_from_euler(0, cam_yaw, 0, &g_player->rotation);
|
|
g_player->dirty = 1;
|
|
}
|
|
update_camera();
|
|
}
|
|
|
|
static void on_key(Engine* engine, int key) {
|
|
if (key == VK_ESCAPE) engine_request_quit(engine);
|
|
}
|
|
|
|
static void on_mouse_move(Engine* engine, int x, int y) {
|
|
(void)engine;
|
|
if (g_mouse_down[0]) {
|
|
if (g_mouse_first) { g_last_mx = x; g_last_my = y; g_mouse_first = 0; }
|
|
else {
|
|
cam_yaw += (float)(x - g_last_mx) * 0.005f;
|
|
cam_pitch += (float)(y - g_last_my) * 0.003f;
|
|
if (cam_pitch > 1.2f) cam_pitch = 1.2f;
|
|
if (cam_pitch < -0.2f) cam_pitch = -0.2f;
|
|
g_last_mx = x; g_last_my = y;
|
|
update_camera();
|
|
}
|
|
} else { g_mouse_first = 1; }
|
|
}
|
|
|
|
static void on_mouse_button(Engine* engine, int button, int pressed) {
|
|
(void)engine;
|
|
if (button >= 0 && button < 3) g_mouse_down[button] = pressed;
|
|
}
|
|
|
|
static void on_resize(Engine* engine, int width, int height) {
|
|
Renderer* r = engine_get_renderer(engine);
|
|
if (r && width > 0 && height > 0) {
|
|
renderer_resize(r, width, height);
|
|
g_camera.aspect = (float)width / (float)height;
|
|
g_camera.dirty = 1;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
(void)argc; (void)argv;
|
|
|
|
EngineConfig config = engine_default_config();
|
|
config.app_name = "Lity Explorer";
|
|
config.vsync = 0;
|
|
config.window_width = 1280;
|
|
config.window_height = 720;
|
|
|
|
Engine* engine = engine_create();
|
|
if (!engine_init(engine, &config)) { LOG_FATAL("Init failed"); return -1; }
|
|
|
|
GraphicsDevice* dev = engine_get_graphics_device(engine);
|
|
Renderer* r = engine_get_renderer(engine);
|
|
|
|
g_assets = asset_manager_create();
|
|
g_shader_asset = asset_manager_load_shader(g_assets, dev->device, NULL, NULL);
|
|
if (!g_shader_asset) { LOG_FATAL("Shader failed"); return -1; }
|
|
|
|
g_scene = create_world(g_assets, dev->device);
|
|
|
|
float aspect = (float)config.window_width / config.window_height;
|
|
g_camera = camera_perspective(1.0472f, aspect, 0.1f, 200.0f);
|
|
g_camera.position = (Vec3){0, cam_height, -8 - cam_dist};
|
|
g_camera.target = (Vec3){0, 0.5f, -8};
|
|
g_camera.dirty = 1;
|
|
|
|
engine_set_update_callback(engine, on_update);
|
|
engine_set_render_callback(engine, on_render);
|
|
engine_set_key_callback(engine, on_key);
|
|
engine_set_mouse_move_callback(engine, on_mouse_move);
|
|
engine_set_mouse_button_callback(engine, on_mouse_button);
|
|
engine_set_resize_callback(engine, on_resize);
|
|
|
|
LOG_INFO("Lity Explorer started!");
|
|
engine_run(engine);
|
|
|
|
scene_destroy_renderers(g_scene);
|
|
scene_destroy(g_scene);
|
|
free(g_scene);
|
|
asset_manager_destroy(g_assets);
|
|
engine_shutdown(engine);
|
|
return 0;
|
|
}
|