fix: .gitignore + add 44 language JSON files
This commit is contained in:
1 parent
e8fd68e27b
commit
8de545dd2c
227 files changed
+22603
No files matched your search
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{A5A5A5A5-5A5A-5A5A-5A5A-5A5A5A5A5A5A}</ProjectGuid>
|
||||
<RootNamespace>Demo</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdc17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)Engine\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;d3dcompiler.lib;xaudio2.lib;xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdc17</LanguageStandard>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)Engine\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>d3d11.lib;dxgi.lib;d3dcompiler.lib;xaudio2.lib;xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,118 @@
|
||||
// ============================================================================
|
||||
// audio_demo.c - XAudio2 音频系统演示
|
||||
// 生成 440Hz 正弦波并播放 2 秒,无需外部 WAV 文件
|
||||
// ============================================================================
|
||||
|
||||
#include "../Engine/Audio/audio.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <windows.h>
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
// 生成标准 PCM WAV 数据 (44.1kHz, 16bit, 单声道)
|
||||
static uint8_t* generate_sine_wave_wav(float frequency, float duration_sec, uint32_t* out_size) {
|
||||
const uint32_t sample_rate = 44100;
|
||||
const uint16_t channels = 1;
|
||||
const uint16_t bits_per_sample = 16;
|
||||
const uint16_t block_align = channels * bits_per_sample / 8;
|
||||
const uint32_t byte_rate = sample_rate * block_align;
|
||||
const uint32_t num_samples = (uint32_t)(sample_rate * duration_sec);
|
||||
const uint32_t data_size = num_samples * block_align;
|
||||
const uint32_t file_size = 44 + data_size;
|
||||
|
||||
uint8_t* wav = (uint8_t*)malloc(file_size);
|
||||
if (!wav) return NULL;
|
||||
|
||||
// RIFF 头
|
||||
memcpy(wav + 0, "RIFF", 4);
|
||||
memcpy(wav + 4, &file_size, 4);
|
||||
memcpy(wav + 8, "WAVE", 4);
|
||||
|
||||
// fmt chunk
|
||||
memcpy(wav + 12, "fmt ", 4);
|
||||
uint32_t fmt_size = 16;
|
||||
memcpy(wav + 16, &fmt_size, 4);
|
||||
uint16_t audio_format = 1; // PCM
|
||||
memcpy(wav + 20, &audio_format, 2);
|
||||
memcpy(wav + 22, &channels, 2);
|
||||
memcpy(wav + 24, &sample_rate, 4);
|
||||
memcpy(wav + 28, &byte_rate, 4);
|
||||
memcpy(wav + 32, &block_align, 2);
|
||||
memcpy(wav + 34, &bits_per_sample, 2);
|
||||
|
||||
// data chunk
|
||||
memcpy(wav + 36, "data", 4);
|
||||
memcpy(wav + 40, &data_size, 4);
|
||||
|
||||
// 生成正弦波样本
|
||||
int16_t* samples = (int16_t*)(wav + 44);
|
||||
float amplitude = 0.3f; // 避免削波
|
||||
for (uint32_t i = 0; i < num_samples; i++) {
|
||||
float t = (float)i / (float)sample_rate;
|
||||
// 简单淡出,避免咔嗒声
|
||||
float envelope = 1.0f;
|
||||
if (i < 1000) envelope = (float)i / 1000.0f;
|
||||
if (i > num_samples - 1000) envelope = (float)(num_samples - i) / 1000.0f;
|
||||
float sample = sinf(2.0f * 3.14159265f * frequency * t) * amplitude * envelope;
|
||||
samples[i] = (int16_t)(sample * 32767.0f);
|
||||
}
|
||||
|
||||
*out_size = file_size;
|
||||
return wav;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
(void)argc; (void)argv;
|
||||
|
||||
printf("Lity3D - Audio Demo\n");
|
||||
printf("========================\n");
|
||||
|
||||
AudioSystem* audio = audio_create();
|
||||
if (!audio) {
|
||||
printf("ERROR: Failed to create XAudio2 audio system\n");
|
||||
return 1;
|
||||
}
|
||||
printf("XAudio2 audio system created.\n");
|
||||
|
||||
AudioSource* source = audio_source_create(audio);
|
||||
if (!source) {
|
||||
printf("ERROR: Failed to create audio source\n");
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t wav_size = 0;
|
||||
uint8_t* wav_data = generate_sine_wave_wav(440.0f, 2.0f, &wav_size);
|
||||
if (!wav_data) {
|
||||
printf("ERROR: Failed to generate sine wave\n");
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!audio_load_wav_memory(source, wav_data, wav_size)) {
|
||||
printf("ERROR: Failed to load generated WAV into audio source\n");
|
||||
free(wav_data);
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
free(wav_data);
|
||||
printf("Generated 440Hz sine wave loaded.\n");
|
||||
|
||||
printf("Playing 2 seconds...\n");
|
||||
audio_source_play(source);
|
||||
|
||||
// 等待播放结束 (约 2 秒 + 缓冲)
|
||||
Sleep(2500);
|
||||
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
|
||||
printf("Audio demo finished successfully.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include "../Engine/Core/timer.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Rendering/mesh.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include "../Engine/Editor/glyph_atlas.h"
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static Mesh* g_tri = NULL;
|
||||
static GlyphAtlas g_atlas;
|
||||
static ID3D11VertexShader* g_tvs = NULL;
|
||||
static ID3D11PixelShader* g_tps = NULL;
|
||||
static ID3D11InputLayout* g_tlayout = NULL;
|
||||
static ID3D11BlendState* g_tblend = NULL;
|
||||
static ID3D11SamplerState* g_tsampler = NULL;
|
||||
static ID3D11Buffer* g_tcb = NULL;
|
||||
static ID3D11DepthStencilState* g_no_depth = NULL;
|
||||
|
||||
typedef struct { float p[3], n[3], uv[2], c[4]; } V;
|
||||
|
||||
static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float w, float h, float r, float g, float b, float a) {
|
||||
V v[4] = {
|
||||
{{x,y,0},{0,0,-1},{0,0},{r,g,b,a}},
|
||||
{{x+w,y,0},{0,0,-1},{1,0},{r,g,b,a}},
|
||||
{{x+w,y+h,0},{0,0,-1},{1,1},{r,g,b,a}},
|
||||
{{x,y+h,0},{0,0,-1},{0,1},{r,g,b,a}},
|
||||
};
|
||||
uint32_t idx[6] = {0,1,2, 0,2,3};
|
||||
ID3D11Buffer *vb = NULL, *ib = NULL;
|
||||
D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0};
|
||||
bd.ByteWidth = sizeof(V)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &vb);
|
||||
bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &ib);
|
||||
UINT stride = sizeof(V), offset = 0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &vb, &stride, &offset);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx, ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
float sw = (float)g_dev->width;
|
||||
float sh = (float)g_dev->height;
|
||||
|
||||
graphics_device_clear(g_dev, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
float proj[64] = {0};
|
||||
proj[0] = 2.0f / sw; proj[5] = -2.0f / sh;
|
||||
proj[10] = 1.0f; proj[12] = -1.0f; proj[13] = 1.0f; proj[15] = 1.0f;
|
||||
Mat4 proj_m, proj_t;
|
||||
memcpy(&proj_m, proj, sizeof(Mat4));
|
||||
mat4_transpose(&proj_m, &proj_t);
|
||||
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = sw; vp.Height = sh; vp.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
|
||||
|
||||
D3D11_RASTERIZER_DESC rdesc = {0};
|
||||
rdesc.FillMode = D3D11_FILL_SOLID;
|
||||
rdesc.CullMode = D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rstate = NULL;
|
||||
g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device, &rdesc, &rstate);
|
||||
ctx->lpVtbl->RSSetState(ctx, rstate);
|
||||
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&proj_t);
|
||||
mesh_draw(g_tri, ctx);
|
||||
|
||||
{
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx, g_no_depth, 0);
|
||||
}
|
||||
|
||||
draw_quad(ctx, sw - 200, 10, 180, 60, 1, 1, 1, 1);
|
||||
|
||||
if (g_tvs && g_tps && g_tlayout && g_tcb && g_tblend && g_tsampler && g_atlas.srv) {
|
||||
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_tcb, 0, NULL, &proj_t, 0, 0);
|
||||
ctx->lpVtbl->VSSetShader(ctx, g_tvs, NULL, 0);
|
||||
ctx->lpVtbl->PSSetShader(ctx, g_tps, NULL, 0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx, g_tlayout);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_tcb);
|
||||
ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_atlas.srv);
|
||||
ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &g_tsampler);
|
||||
ctx->lpVtbl->OMSetBlendState(ctx, g_tblend, NULL, 0xFFFFFFFF);
|
||||
|
||||
typedef struct { float p[3], n[3], uv[2], c[4]; } TV;
|
||||
TV tverts[4];
|
||||
uint32_t tidx[6] = {0,1,2, 0,2,3};
|
||||
int cx = (int)(sw - 195), cy = 35;
|
||||
for (const wchar_t* p = L"\u6d4b\u8bd5"; *p; p++) {
|
||||
float u0, v0, u1, v1, adv_x, adv_y;
|
||||
if (glyph_atlas_get_or_create(&g_atlas, g_dev->device, ctx, *p, &u0, &v0, &u1, &v1, &adv_x, &adv_y)) {
|
||||
tverts[0] = (TV){{(float)cx,(float)cy,0},{0,0,1},{u0,v0},{0,0,0,1}};
|
||||
tverts[1] = (TV){{(float)cx+adv_x,(float)cy,0},{0,0,1},{u1,v0},{0,0,0,1}};
|
||||
tverts[2] = (TV){{(float)cx+adv_x,(float)cy+adv_y,0},{0,0,1},{u1,v1},{0,0,0,1}};
|
||||
tverts[3] = (TV){{(float)cx,(float)cy+adv_y,0},{0,0,1},{u0,v1},{0,0,0,1}};
|
||||
ID3D11Buffer *tvb = NULL, *tib = NULL;
|
||||
D3D11_BUFFER_DESC bd2 = {0}; D3D11_SUBRESOURCE_DATA sd2 = {0};
|
||||
bd2.ByteWidth = sizeof(TV)*4; bd2.Usage = D3D11_USAGE_DEFAULT; bd2.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd2.pSysMem = tverts; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd2, &sd2, &tvb);
|
||||
bd2.ByteWidth = sizeof(uint32_t)*6; bd2.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd2.pSysMem = tidx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd2, &sd2, &tib);
|
||||
UINT stride2 = sizeof(TV), offset2 = 0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &tvb, &stride2, &offset2);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx, tib, DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0);
|
||||
tib->lpVtbl->Release(tib); tvb->lpVtbl->Release(tvb);
|
||||
cx += (int)adv_x + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rstate) rstate->lpVtbl->Release(rstate);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
(void)hInstance; (void)hPrevInstance; (void)lpCmdLine; (void)nCmdShow;
|
||||
LOG_INFO("=== Compatibility Test ===");
|
||||
|
||||
EngineConfig config = engine_default_config();
|
||||
config.app_name = "Compatibility Test";
|
||||
config.vsync = 1;
|
||||
config.window_width = 1280;
|
||||
config.window_height = 720;
|
||||
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &config)) return -1;
|
||||
|
||||
g_dev = graphics_device_create();
|
||||
if (!graphics_device_init(g_dev, window_get_handle(engine->window), config.window_width, config.window_height, 1)) {
|
||||
LOG_FATAL("D3D11 init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_shader = shader_create();
|
||||
shader_compile(g_shader, g_dev->device, NULL, NULL, 0, 0);
|
||||
|
||||
glyph_atlas_init(&g_atlas, g_dev->device);
|
||||
|
||||
const char* tvs_src = "cbuffer CB:register(b0){float4x4 WVP;};struct VS_IN{float4 pos:POSITION;float3 n:NORMAL;float2 uv:TEXCOORD;float4 col:COLOR;};struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};PS_IN main(VS_IN i){PS_IN o;o.pos=mul(i.pos,WVP);o.uv=i.uv;o.col=i.col;return o;}";
|
||||
const char* tps_src = "Texture2D tex:register(t0);SamplerState smp:register(s0);struct PS_IN{float4 pos:SV_POSITION;float2 uv:TEXCOORD;float4 col:COLOR;};float4 main(PS_IN i):SV_TARGET{float a=tex.Sample(smp,i.uv).a;return float4(i.col.rgb,i.col.a*a);}";
|
||||
ID3DBlob *vsb = NULL, *psb = NULL, *err = NULL;
|
||||
D3DCompile(tvs_src, (UINT)strlen(tvs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vsb, &err);
|
||||
if (err) { err->lpVtbl->Release(err); err = NULL; }
|
||||
D3DCompile(tps_src, (UINT)strlen(tps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &psb, &err);
|
||||
if (err) { err->lpVtbl->Release(err); err = NULL; }
|
||||
if (vsb && psb) {
|
||||
g_dev->device->lpVtbl->CreateVertexShader(g_dev->device, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), NULL, &g_tvs);
|
||||
g_dev->device->lpVtbl->CreatePixelShader(g_dev->device, psb->lpVtbl->GetBufferPointer(psb), psb->lpVtbl->GetBufferSize(psb), NULL, &g_tps);
|
||||
D3D11_INPUT_ELEMENT_DESC layout[] = {
|
||||
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
};
|
||||
g_dev->device->lpVtbl->CreateInputLayout(g_dev->device, layout, 4, vsb->lpVtbl->GetBufferPointer(vsb), vsb->lpVtbl->GetBufferSize(vsb), &g_tlayout);
|
||||
vsb->lpVtbl->Release(vsb); psb->lpVtbl->Release(psb);
|
||||
}
|
||||
D3D11_SAMPLER_DESC sdesc = {0};
|
||||
sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
sdesc.AddressU = sdesc.AddressV = sdesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
g_dev->device->lpVtbl->CreateSamplerState(g_dev->device, &sdesc, &g_tsampler);
|
||||
D3D11_BLEND_DESC bdesc = {0};
|
||||
bdesc.RenderTarget[0].BlendEnable = TRUE;
|
||||
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
bdesc.RenderTarget[0].RenderTargetWriteMask = 0x0F;
|
||||
g_dev->device->lpVtbl->CreateBlendState(g_dev->device, &bdesc, &g_tblend);
|
||||
D3D11_BUFFER_DESC cbd = {0};
|
||||
cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &cbd, NULL, &g_tcb);
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC dsdesc = {0};
|
||||
dsdesc.DepthEnable = FALSE;
|
||||
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device, &dsdesc, &g_no_depth);
|
||||
|
||||
V tri[3] = {
|
||||
{{640, 300, 0}, {0,0,-1}, {0,0}, {1, 0.2f, 0.2f, 1}},
|
||||
{{500, 550, 0}, {0,0,-1}, {0,1}, {0.2f, 1, 0.2f, 1}},
|
||||
{{780, 550, 0}, {0,0,-1}, {1,0}, {0.2f, 0.2f, 1, 1}},
|
||||
};
|
||||
uint32_t idx[3] = {0, 1, 2};
|
||||
g_tri = (Mesh*)calloc(1, sizeof(Mesh));
|
||||
g_tri->stride = sizeof(V); g_tri->vcount = 3; g_tri->icount = 3;
|
||||
D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0};
|
||||
bd.ByteWidth = sizeof(V)*3; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = tri; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &g_tri->vb);
|
||||
bd.ByteWidth = sizeof(uint32_t)*3; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device, &bd, &sd, &g_tri->ib);
|
||||
|
||||
engine_set_render_callback(engine, on_render);
|
||||
engine_set_key_callback(engine, on_key);
|
||||
LOG_INFO("Running...");
|
||||
engine_run(engine);
|
||||
|
||||
mesh_destroy(g_tri);
|
||||
shader_destroy(g_shader);
|
||||
glyph_atlas_destroy(&g_atlas);
|
||||
graphics_device_destroy(g_dev);
|
||||
engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
static ID3D11Device* g_dev; static ID3D11DeviceContext* g_ctx;
|
||||
static IDXGISwapChain* g_sc; static ID3D11RenderTargetView* g_rtv;
|
||||
static ID3D11VertexShader* g_vs; static ID3D11PixelShader* g_ps;
|
||||
static ID3D11InputLayout* g_il; static ID3D11Buffer* g_cb;
|
||||
|
||||
static int key_l=0,key_r=0,key_u=0,key_d=0,key_sp=0;
|
||||
static int dead=0, score=0;
|
||||
static float px=0, py=0, speed=0.4f;
|
||||
#define NOBS 15
|
||||
static float ox[NOBS],oy[NOBS],oz[NOBS],osz[NOBS];
|
||||
static int oa[NOBS],oc=0; static float st=0;
|
||||
|
||||
static void Init(HWND h){
|
||||
HRESULT hr;DXGI_SWAP_CHAIN_DESC sd;memset(&sd,0,sizeof(sd));sd.BufferCount=2;sd.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;sd.BufferDesc.RefreshRate.Numerator=60;sd.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;sd.OutputWindow=h;sd.SampleDesc.Count=1;sd.Windowed=TRUE;sd.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_11_0,gt;hr=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,&fl,1,D3D11_SDK_VERSION,&sd,&g_sc,&g_dev,>,&g_ctx);if(FAILED(hr))return;
|
||||
ID3D11Texture2D*bb=NULL;hr=g_sc->lpVtbl->GetBuffer(g_sc,0,&IID_ID3D11Texture2D,(void**)&bb);if(FAILED(hr)||!bb)return;hr=g_dev->lpVtbl->CreateRenderTargetView(g_dev,(ID3D11Resource*)bb,NULL,&g_rtv);bb->lpVtbl->Release(bb);if(FAILED(hr))return;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.c=i.c;return o;}";
|
||||
const char*ps="float4 main(float4 p:SV_POSITION, float4 c:COLOR):SV_Target{return c;}";
|
||||
ID3DBlob*b1,*b2,*e;D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);if(e){e->lpVtbl->Release(e);e=NULL;}D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);if(e){e->lpVtbl->Release(e);e=NULL;}if(!b1||!b2)return;
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);g_dev->lpVtbl->CreatePixelShader(g_dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];memset(el,0,sizeof(el));el[0].SemanticName="POSITION";el[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[1].SemanticName="NORMAL";el[1].AlignedByteOffset=12;el[1].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[2].SemanticName="TEXCOORD";el[2].AlignedByteOffset=24;el[2].Format=DXGI_FORMAT_R32G32_FLOAT;el[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[3].SemanticName="COLOR";el[3].AlignedByteOffset=32;el[3].Format=DXGI_FORMAT_R32G32B32A32_FLOAT;el[3].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev,el,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;memset(&cbd,0,sizeof(cbd));cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;g_dev->lpVtbl->CreateBuffer(g_dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void Cube(float cx,float cy,float cz,float s,float cr,float cg,float cb){
|
||||
V3D v[24];float f[6][4][3]={{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}};float nm[6][3]={{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for(int fi=0;fi<6;fi++)for(int vi=0;vi<4;vi++){int i=fi*4+vi;v[i].p[0]=f[fi][vi][0]*s+cx;v[i].p[1]=f[fi][vi][1]*s+cy;v[i].p[2]=f[fi][vi][2]*s+cz;v[i].n[0]=nm[fi][0];v[i].n[1]=nm[fi][1];v[i].n[2]=nm[fi][2];v[i].c[0]=cr;v[i].c[1]=cg;v[i].c[2]=cb;v[i].c[3]=1;}
|
||||
uint32_t ix[36];for(int fi=0;fi<6;fi++){int b=fi*4;ix[fi*6]=b;ix[fi*6+1]=b+1;ix[fi*6+2]=b+2;ix[fi*6+3]=b;ix[fi*6+4]=b+2;ix[fi*6+5]=b+3;}
|
||||
ID3D11Buffer*vb,*ib;D3D11_BUFFER_DESC bd;D3D11_SUBRESOURCE_DATA sd;memset(&bd,0,sizeof(bd));memset(&sd,0,sizeof(sd));bd.ByteWidth=sizeof(V3D)*24;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;sd.pSysMem=v;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&vb);bd.ByteWidth=sizeof(uint32_t)*36;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;sd.pSysMem=ix;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V3D),o=0;g_ctx->lpVtbl->IASetVertexBuffers(g_ctx,0,1,&vb,&s2,&o);g_ctx->lpVtbl->IASetIndexBuffer(g_ctx,ib,DXGI_FORMAT_R32_UINT,0);g_ctx->lpVtbl->DrawIndexed(g_ctx,36,0,0);ib->lpVtbl->Release(ib);vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void Spawn(void){for(int i=0;i<NOBS;i++){if(!oa[i]){oa[i]=1;ox[i]=-1.0f+(float)(rand()%200)/100.0f;oy[i]=-0.6f+(float)(rand()%120)/100.0f;oz[i]=1.95f;osz[i]=0.08f+(float)(rand()%80)/400.0f;oc++;return;}}}
|
||||
|
||||
static void Frame(void){
|
||||
float dt=0.016f,spd=speed*dt;
|
||||
if(dead){if(key_sp){dead=0;score=0;speed=0.4f;px=py=0;oc=0;st=0;for(int i=0;i<NOBS;i++)oa[i]=0;}}
|
||||
else{
|
||||
if(key_l)px-=spd;if(key_r)px+=spd;if(key_u)py+=spd;if(key_d)py-=spd;
|
||||
if(px<-1.3f)px=-1.3f;if(px>1.3f)px=1.3f;if(py<-0.9f)py=-0.9f;if(py>0.9f)py=0.9f;
|
||||
st+=dt;if(st>0.6f/speed){Spawn();st=0;}
|
||||
for(int i=0;i<NOBS;i++){
|
||||
if(!oa[i])continue;oz[i]-=speed*dt;
|
||||
if(oz[i]<1.0f){oa[i]=0;oc--;score++;speed=0.4f+score*0.05f;if(speed>2.0f)speed=2.0f;}
|
||||
float dx=px>ox[i]?px-ox[i]:ox[i]-px;float dy=py>oy[i]?py-oy[i]:oy[i]-py;float dz=1.5f>oz[i]?1.5f-oz[i]:oz[i]-1.5f;
|
||||
float md=0.12f+osz[i];if(dx<md&&dy<md&&dz<md)dead=1;
|
||||
}
|
||||
}
|
||||
|
||||
float fov=1.0f/tanf(0.4f),asp=1280.0f/720.0f;
|
||||
float mvp[16];memset(mvp,0,sizeof(mvp));
|
||||
mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
|
||||
float cl[4]={.08f,.1f,.14f,1};if(dead){cl[0]=.12f;cl[1]=.02f;cl[2]=.02f;}
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx,1,&g_rtv,NULL);g_ctx->lpVtbl->ClearRenderTargetView(g_ctx,g_rtv,cl);
|
||||
D3D11_VIEWPORT vp;memset(&vp,0,sizeof(vp));vp.Width=1280;vp.Height=720;vp.MaxDepth=1;g_ctx->lpVtbl->RSSetViewports(g_ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd;memset(&rd,0,sizeof(rd));rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;ID3D11RasterizerState*rs;g_dev->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);g_ctx->lpVtbl->RSSetState(g_ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds;memset(&ds,0,sizeof(ds));ds.DepthEnable=FALSE;ID3D11DepthStencilState*dss;g_dev->lpVtbl->CreateDepthStencilState(g_dev,&ds,&dss);g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx,dss,0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);g_ctx->lpVtbl->VSSetShader(g_ctx,g_vs,NULL,0);g_ctx->lpVtbl->PSSetShader(g_ctx,g_ps,NULL,0);g_ctx->lpVtbl->IASetInputLayout(g_ctx,g_il);g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx,0,1,&g_cb);g_ctx->lpVtbl->UpdateSubresource(g_ctx,(ID3D11Resource*)g_cb,0,NULL,mvp,0,0);
|
||||
|
||||
if(dead){Cube(0,0,1.5f,0.4f,.9f,.1f,.1f);}
|
||||
else{
|
||||
Cube(px,py,1.5f,0.12f,.1f,.9f,.3f);
|
||||
for(int i=0;i<NOBS;i++){if(!oa[i])continue;float fl=.6f+.4f*sinf(oz[i]*8.0f);Cube(ox[i],oy[i],oz[i],osz[i],fl,.15f,.1f);}
|
||||
}
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);g_sc->lpVtbl->Present(g_sc,1,0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h,UINT m,WPARAM w,LPARAM l){switch(m){case WM_KEYDOWN:switch(w){case VK_LEFT:key_l=1;break;case VK_RIGHT:key_r=1;break;case VK_UP:key_u=1;break;case VK_DOWN:key_d=1;break;case 'A':key_l=1;break;case 'D':key_r=1;break;case 'W':key_u=1;break;case 'S':key_d=1;break;case VK_SPACE:key_sp=1;break;case VK_ESCAPE:PostQuitMessage(0);break;}break;case WM_KEYUP:switch(w){case VK_LEFT:key_l=0;break;case VK_RIGHT:key_r=0;break;case VK_UP:key_u=0;break;case VK_DOWN:key_d=0;break;case 'A':key_l=0;break;case 'D':key_r=0;break;case 'W':key_u=0;break;case 'S':key_d=0;break;case VK_SPACE:key_sp=0;break;}break;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProcW(h,m,w,l);}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){srand(42);WNDCLASSEXW wc;memset(&wc,0,sizeof(wc));wc.cbSize=sizeof(wc);wc.style=CS_CLASSDC;wc.lpfnWndProc=WP;wc.hInstance=hI;wc.lpszClassName=L"dodge";RegisterClassExW(&wc);HWND hwnd=CreateWindowW(L"dodge",L"Cube Dodge - WASD/Arrows move, Space restart",WS_OVERLAPPEDWINDOW,200,100,1280,720,NULL,NULL,hI,NULL);if(!hwnd)return -1;ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);Init(hwnd);MSG msg;while(1){while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);if(msg.message==WM_QUIT)goto done;}Frame();}done:if(g_cb)g_cb->lpVtbl->Release(g_cb);if(g_il)g_il->lpVtbl->Release(g_il);if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_rtv)g_rtv->lpVtbl->Release(g_rtv);if(g_sc)g_sc->lpVtbl->Release(g_sc);if(g_ctx)g_ctx->lpVtbl->Release(g_ctx);if(g_dev)g_dev->lpVtbl->Release(g_dev);return 0;}
|
||||
@@ -0,0 +1,95 @@
|
||||
// 独立 D3D11 测试 - 不依赖引擎框架
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <dxgi.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma comment(lib, "d3d11.lib")
|
||||
#pragma comment(lib, "dxgi.lib")
|
||||
|
||||
static ID3D11Device* device = NULL;
|
||||
static ID3D11DeviceContext* context = NULL;
|
||||
static IDXGISwapChain* swap_chain = NULL;
|
||||
static ID3D11RenderTargetView* rtv = NULL;
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (msg == WM_DESTROY) { PostQuitMessage(0); return 0; }
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
(void)hPrevInstance; (void)lpCmdLine; (void)nCmdShow;
|
||||
|
||||
// 注册窗口类
|
||||
WNDCLASSEXW wc = {0};
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.lpszClassName = L"D3D11Test";
|
||||
RegisterClassExW(&wc);
|
||||
|
||||
// 创建窗口
|
||||
HWND hwnd = CreateWindowExW(0, L"D3D11Test", L"D3D11 Test",
|
||||
WS_OVERLAPPEDWINDOW, 100, 100, 800, 600,
|
||||
NULL, NULL, hInstance, NULL);
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
// 创建 D3D11 设备和交换链
|
||||
DXGI_SWAP_CHAIN_DESC scd = {0};
|
||||
scd.BufferCount = 1;
|
||||
scd.BufferDesc.Width = 800;
|
||||
scd.BufferDesc.Height = 600;
|
||||
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
scd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
scd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
scd.OutputWindow = hwnd;
|
||||
scd.SampleDesc.Count = 1;
|
||||
scd.Windowed = TRUE;
|
||||
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
D3D_FEATURE_LEVEL levels[] = {D3D_FEATURE_LEVEL_11_0};
|
||||
HRESULT hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, levels, 1, D3D11_SDK_VERSION, &scd, &swap_chain, &device, NULL, &context);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
MessageBoxW(hwnd, L"D3D11 CreateDevice Failed!", L"Error", MB_OK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 创建渲染目标
|
||||
ID3D11Texture2D* back_buffer = NULL;
|
||||
swap_chain->lpVtbl->GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, (void**)&back_buffer);
|
||||
device->lpVtbl->CreateRenderTargetView(device, (ID3D11Resource*)back_buffer, NULL, &rtv);
|
||||
back_buffer->lpVtbl->Release(back_buffer);
|
||||
|
||||
// 设置渲染目标
|
||||
context->lpVtbl->OMSetRenderTargets(context, 1, &rtv, NULL);
|
||||
|
||||
// 主循环
|
||||
MSG msg = {0};
|
||||
while (msg.message != WM_QUIT) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) break;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
// 清屏 - 蓝色
|
||||
float color[4] = {0.2f, 0.5f, 0.8f, 1.0f};
|
||||
context->lpVtbl->ClearRenderTargetView(context, rtv, color);
|
||||
|
||||
// 呈现
|
||||
swap_chain->lpVtbl->Present(swap_chain, 0, 0);
|
||||
}
|
||||
|
||||
// 清理
|
||||
rtv->lpVtbl->Release(rtv);
|
||||
swap_chain->lpVtbl->Release(swap_chain);
|
||||
context->lpVtbl->Release(context);
|
||||
device->lpVtbl->Release(device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,682 @@
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.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/material.h"
|
||||
#include "../Engine/Rendering/mesh.h"
|
||||
#include "../Engine/Rendering/camera.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/Scene/scene_render.h"
|
||||
#include "../Engine/Scene/scene_serialize.h"
|
||||
#include "../Engine/Editor/glyph_atlas.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <d3dcompiler.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <Windows.h>
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Editor state */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static Engine* g_engine = NULL;
|
||||
static GraphicsDevice* g_gdev = NULL;
|
||||
static Renderer* g_renderer = NULL;
|
||||
static AssetManager* g_assets = NULL;
|
||||
static Asset* g_shader_asset = NULL;
|
||||
static Scene* g_scene = NULL;
|
||||
static Camera g_camera;
|
||||
|
||||
static GlyphAtlas g_atlas;
|
||||
static int g_atlas_ok = 0;
|
||||
|
||||
static SceneNode* g_selected = NULL;
|
||||
static int g_mouse_x = 0;
|
||||
static int g_mouse_y = 0;
|
||||
static int g_mouse_down[3] = {0};
|
||||
static int g_mouse_last_x = 0;
|
||||
static int g_mouse_last_y = 0;
|
||||
static int g_camera_drag = 0;
|
||||
|
||||
static char g_console[16][256];
|
||||
static int g_console_count = 0;
|
||||
static char g_status[256] = "";
|
||||
|
||||
/* UI metrics */
|
||||
#define ED_MENU_H 30
|
||||
#define ED_TOOLBAR_H 30
|
||||
#define ED_LEFT_W 240
|
||||
#define ED_RIGHT_W 260
|
||||
#define ED_BOTTOM_H 180
|
||||
#define ED_SPLITTER 1
|
||||
|
||||
/* UI D3D resources */
|
||||
static ID3D11DepthStencilState* g_ui_depth = NULL;
|
||||
static ID3D11RasterizerState* g_ui_raster = NULL;
|
||||
static ID3D11BlendState* g_ui_blend = NULL;
|
||||
static ID3D11SamplerState* g_ui_sampler = NULL;
|
||||
static ID3D11Buffer* g_ui_cb = NULL;
|
||||
static ID3D11VertexShader* g_ui_vs = NULL;
|
||||
static ID3D11PixelShader* g_ui_ps = NULL;
|
||||
static ID3D11InputLayout* g_ui_layout = NULL;
|
||||
static ID3D11VertexShader* g_text_vs = NULL;
|
||||
static ID3D11PixelShader* g_text_ps = NULL;
|
||||
static ID3D11InputLayout* g_text_layout = NULL;
|
||||
|
||||
typedef struct { float p[3], n[3], uv[2], c[4]; } UIVertex;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Console */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void console_add(const char* msg) {
|
||||
if (g_console_count >= 16) {
|
||||
for (int i = 0; i < 15; i++) strcpy(g_console[i], g_console[i+1]);
|
||||
g_console_count = 15;
|
||||
}
|
||||
strncpy(g_console[g_console_count], msg, 255);
|
||||
g_console[g_console_count][255] = 0;
|
||||
g_console_count++;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Shader helpers */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static ID3DBlob* compile_blob(const char* code, const char* target) {
|
||||
ID3DBlob *blob = NULL, *err = NULL;
|
||||
D3DCompile(code, strlen(code), NULL, NULL, NULL, "main", target,
|
||||
D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR, 0, &blob, &err);
|
||||
if (err) {
|
||||
LOG_ERROR("Editor shader compile (%s): %s", target, (char*)err->lpVtbl->GetBufferPointer(err));
|
||||
err->lpVtbl->Release(err);
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
static int compile_ui_shaders(ID3D11Device* dev) {
|
||||
const char* vs =
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"struct I{float4 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"O main(I i){O o;o.p=mul(i.p,WVP);o.u=i.u;o.c=i.c;return o;}";
|
||||
const char* ps =
|
||||
"struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"float4 main(O i):SV_TARGET{return i.c;}";
|
||||
const char* tps =
|
||||
"Texture2D t:register(t0);SamplerState s:register(s0);"
|
||||
"struct O{float4 p:SV_POSITION;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"float4 main(O i):SV_TARGET{float a=t.Sample(s,i.u).a;return float4(i.c.rgb,i.c.a*a);}";
|
||||
|
||||
ID3DBlob *b1 = compile_blob(vs, "vs_5_0"), *b2 = compile_blob(ps, "ps_5_0"), *b3 = compile_blob(tps, "ps_5_0");
|
||||
if (!b1 || !b2 || !b3) return 0;
|
||||
|
||||
dev->lpVtbl->CreateVertexShader(dev, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), NULL, &g_ui_vs);
|
||||
dev->lpVtbl->CreatePixelShader(dev, b2->lpVtbl->GetBufferPointer(b2), b2->lpVtbl->GetBufferSize(b2), NULL, &g_ui_ps);
|
||||
dev->lpVtbl->CreatePixelShader(dev, b3->lpVtbl->GetBufferPointer(b3), b3->lpVtbl->GetBufferSize(b3), NULL, &g_text_ps);
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC layout[] = {
|
||||
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
};
|
||||
dev->lpVtbl->CreateInputLayout(dev, layout, 4, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), &g_ui_layout);
|
||||
g_text_layout = g_ui_layout;
|
||||
g_text_vs = g_ui_vs;
|
||||
|
||||
b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2); b3->lpVtbl->Release(b3);
|
||||
return g_ui_vs && g_ui_ps && g_text_ps && g_ui_layout;
|
||||
}
|
||||
|
||||
static void create_ui_states(ID3D11Device* dev) {
|
||||
D3D11_DEPTH_STENCIL_DESC dsd = {0};
|
||||
dsd.DepthEnable = FALSE; dsd.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
|
||||
dev->lpVtbl->CreateDepthStencilState(dev, &dsd, &g_ui_depth);
|
||||
|
||||
D3D11_RASTERIZER_DESC rd = {0};
|
||||
rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE;
|
||||
dev->lpVtbl->CreateRasterizerState(dev, &rd, &g_ui_raster);
|
||||
|
||||
D3D11_BLEND_DESC bd = {0};
|
||||
bd.RenderTarget[0].BlendEnable = TRUE;
|
||||
bd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
|
||||
bd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
|
||||
bd.RenderTarget[0].BlendOp = bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
bd.RenderTarget[0].RenderTargetWriteMask = 0x0F;
|
||||
dev->lpVtbl->CreateBlendState(dev, &bd, &g_ui_blend);
|
||||
|
||||
D3D11_SAMPLER_DESC sd = {0};
|
||||
sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
dev->lpVtbl->CreateSamplerState(dev, &sd, &g_ui_sampler);
|
||||
|
||||
D3D11_BUFFER_DESC cbd = {0};
|
||||
cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
dev->lpVtbl->CreateBuffer(dev, &cbd, NULL, &g_ui_cb);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* UI rendering */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void ui_set_projection(ID3D11DeviceContext* ctx, float sw, float sh) {
|
||||
float proj[16] = {0};
|
||||
proj[0] = 2.0f / sw; proj[5] = -2.0f / sh;
|
||||
proj[10] = 1.0f; proj[12] = -1.0f; proj[13] = 1.0f; proj[15] = 1.0f;
|
||||
ctx->lpVtbl->UpdateSubresource(ctx, (ID3D11Resource*)g_ui_cb, 0, NULL, proj, 0, 0);
|
||||
}
|
||||
|
||||
static void ui_setup_solid(ID3D11DeviceContext* ctx) {
|
||||
ctx->lpVtbl->VSSetShader(ctx, g_ui_vs, NULL, 0);
|
||||
ctx->lpVtbl->PSSetShader(ctx, g_ui_ps, NULL, 0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx, g_ui_layout);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_ui_cb);
|
||||
ctx->lpVtbl->OMSetBlendState(ctx, NULL, NULL, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static void ui_setup_text(ID3D11DeviceContext* ctx) {
|
||||
ctx->lpVtbl->VSSetShader(ctx, g_text_vs, NULL, 0);
|
||||
ctx->lpVtbl->PSSetShader(ctx, g_text_ps, NULL, 0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx, g_text_layout);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx, 0, 1, &g_ui_cb);
|
||||
ctx->lpVtbl->PSSetShaderResources(ctx, 0, 1, &g_atlas.srv);
|
||||
ctx->lpVtbl->PSSetSamplers(ctx, 0, 1, &g_ui_sampler);
|
||||
ctx->lpVtbl->OMSetBlendState(ctx, g_ui_blend, NULL, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static void ui_begin(ID3D11DeviceContext* ctx, float sw, float sh) {
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = sw; vp.Height = sh; vp.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
|
||||
ctx->lpVtbl->RSSetState(ctx, g_ui_raster);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx, g_ui_depth, 0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ui_set_projection(ctx, sw, sh);
|
||||
ui_setup_solid(ctx);
|
||||
}
|
||||
|
||||
static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float w, float h,
|
||||
float r, float g, float b, float a) {
|
||||
UIVertex v[4] = {
|
||||
{{x, y, 0},{0,0,-1},{0,0},{r,g,b,a}},
|
||||
{{x+w, y, 0},{0,0,-1},{1,0},{r,g,b,a}},
|
||||
{{x+w, y+h, 0},{0,0,-1},{1,1},{r,g,b,a}},
|
||||
{{x, y+h, 0},{0,0,-1},{0,1},{r,g,b,a}},
|
||||
};
|
||||
uint32_t idx[6] = {0,1,2, 0,2,3};
|
||||
ID3D11Buffer *vb = NULL, *ib = NULL;
|
||||
D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0};
|
||||
bd.ByteWidth = sizeof(UIVertex)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = v; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &vb);
|
||||
bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = idx; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &ib);
|
||||
UINT stride = sizeof(UIVertex), offset = 0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &vb, &stride, &offset);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx, ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0);
|
||||
if (ib) ib->lpVtbl->Release(ib);
|
||||
if (vb) vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void draw_text(ID3D11DeviceContext* ctx, const wchar_t* text, int x, int y,
|
||||
float r, float g, float b, float a) {
|
||||
if (!g_atlas_ok) return;
|
||||
ui_setup_text(ctx);
|
||||
for (const wchar_t* p = text; *p; p++) {
|
||||
float u0, v0, u1, v1, ax, ay;
|
||||
if (!glyph_atlas_get_or_create(&g_atlas, g_gdev->device, ctx, *p, &u0, &v0, &u1, &v1, &ax, &ay)) continue;
|
||||
UIVertex tv[4] = {
|
||||
{{(float)x, (float)y, 0},{0,0,1},{u0,v0},{r,g,b,a}},
|
||||
{{(float)x + ax, (float)y, 0},{0,0,1},{u1,v0},{r,g,b,a}},
|
||||
{{(float)x + ax, (float)y + ay, 0},{0,0,1},{u1,v1},{r,g,b,a}},
|
||||
{{(float)x, (float)y + ay, 0},{0,0,1},{u0,v1},{r,g,b,a}},
|
||||
};
|
||||
uint32_t ti[6] = {0,1,2, 0,2,3};
|
||||
ID3D11Buffer *tvb = NULL, *tib = NULL;
|
||||
D3D11_BUFFER_DESC bd = {0}; D3D11_SUBRESOURCE_DATA sd = {0};
|
||||
bd.ByteWidth = sizeof(UIVertex)*4; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = tv; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &tvb);
|
||||
bd.ByteWidth = sizeof(uint32_t)*6; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = ti; g_gdev->device->lpVtbl->CreateBuffer(g_gdev->device, &bd, &sd, &tib);
|
||||
UINT stride = sizeof(UIVertex), offset = 0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx, 0, 1, &tvb, &stride, &offset);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx, tib, DXGI_FORMAT_R32_UINT, 0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx, 6, 0, 0);
|
||||
if (tib) tib->lpVtbl->Release(tib);
|
||||
if (tvb) tvb->lpVtbl->Release(tvb);
|
||||
x += (int)ax + 1;
|
||||
}
|
||||
ui_setup_solid(ctx);
|
||||
}
|
||||
|
||||
static void draw_text_a(ID3D11DeviceContext* ctx, const char* text, int x, int y,
|
||||
float r, float g, float b, float a) {
|
||||
wchar_t buf[256];
|
||||
int n = (int)strlen(text); if (n > 255) n = 255;
|
||||
for (int i = 0; i < n; i++) buf[i] = (wchar_t)text[i];
|
||||
buf[n] = 0;
|
||||
draw_text(ctx, buf, x, y, r, g, b, a);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Scene helpers */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static SceneNode* create_primitive(Scene* scene, SceneNode* parent, AssetManager* am,
|
||||
ID3D11Device* dev, const char* name, MeshType type,
|
||||
Vec3 pos, Vec3 rot, Vec3 scale, Material* mat) {
|
||||
SceneNode* node = scene_create_node(scene, name);
|
||||
if (!node) return NULL;
|
||||
if (parent) scene_set_parent(node, parent);
|
||||
node->position = pos;
|
||||
node->scale = scale;
|
||||
quat_from_euler(rot.x, rot.y, rot.z, &node->rotation);
|
||||
|
||||
Asset* mesh_asset = asset_manager_load_mesh(am, dev, name);
|
||||
if (!mesh_asset) {
|
||||
const char* builtin = NULL;
|
||||
if (type == MESH_CUBE) builtin = "cube";
|
||||
else if (type == MESH_SPHERE) builtin = "sphere";
|
||||
else if (type == MESH_PLANE) builtin = "plane";
|
||||
if (builtin) mesh_asset = asset_manager_load_mesh(am, dev, builtin);
|
||||
}
|
||||
if (mesh_asset && mat) {
|
||||
MeshRenderer* mr = mesh_renderer_create(type, (Mesh*)asset_data(mesh_asset), mat);
|
||||
scene_node_set_mesh_renderer(node, mr);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static Scene* create_default_editor_scene(AssetManager* am, ID3D11Device* dev, Shader* shader) {
|
||||
Scene* scene = (Scene*)malloc(sizeof(Scene));
|
||||
if (!scene) return NULL;
|
||||
scene_init(scene);
|
||||
strncpy(scene->root->name, "root", sizeof(scene->root->name) - 1);
|
||||
|
||||
Material* mat_red = material_create(shader, NULL);
|
||||
mat_red->color = (Vec4){1.0f, 0.3f, 0.2f, 1.0f};
|
||||
Material* mat_blue = material_create(shader, NULL);
|
||||
mat_blue->color = (Vec4){0.2f, 0.5f, 1.0f, 1.0f};
|
||||
Material* mat_ground = material_create(shader, NULL);
|
||||
mat_ground->color = (Vec4){0.3f, 0.3f, 0.35f, 1.0f};
|
||||
|
||||
create_primitive(scene, scene->root, am, dev, "cube", MESH_CUBE,
|
||||
(Vec3){0,0,0}, (Vec3){0,0,0}, (Vec3){1,1,1}, mat_red);
|
||||
create_primitive(scene, scene->root, am, dev, "sphere", MESH_SPHERE,
|
||||
(Vec3){2.0f,0,0}, (Vec3){0,0,0}, (Vec3){0.8f,0.8f,0.8f}, mat_blue);
|
||||
create_primitive(scene, scene->root, am, dev, "ground", MESH_PLANE,
|
||||
(Vec3){0,-1.0f,0}, (Vec3){0,0,0}, (Vec3){1,1,1}, mat_ground);
|
||||
|
||||
scene_update(scene);
|
||||
return scene;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Editor UI */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void draw_panel_bg(ID3D11DeviceContext* ctx, float sw, float sh) {
|
||||
float body_h = sh - ED_MENU_H - ED_TOOLBAR_H - ED_BOTTOM_H;
|
||||
|
||||
/* menu bar */
|
||||
draw_quad(ctx, 0, 0, sw, ED_MENU_H, 0.14f, 0.14f, 0.18f, 1.0f);
|
||||
/* toolbar */
|
||||
draw_quad(ctx, 0, ED_MENU_H, sw, ED_TOOLBAR_H, 0.20f, 0.20f, 0.26f, 1.0f);
|
||||
/* separators */
|
||||
draw_quad(ctx, 0, ED_MENU_H, sw, 1, 0.30f, 0.45f, 0.75f, 1.0f);
|
||||
draw_quad(ctx, 0, ED_MENU_H + ED_TOOLBAR_H, sw, 1, 0.30f, 0.45f, 0.75f, 1.0f);
|
||||
/* left panel */
|
||||
draw_quad(ctx, 0, ED_MENU_H + ED_TOOLBAR_H + 1, ED_LEFT_W, body_h, 0.18f, 0.18f, 0.23f, 1.0f);
|
||||
draw_quad(ctx, ED_LEFT_W, ED_MENU_H + ED_TOOLBAR_H + 1, ED_SPLITTER, body_h, 0.30f, 0.45f, 0.75f, 1.0f);
|
||||
/* right panel */
|
||||
draw_quad(ctx, sw - ED_RIGHT_W, ED_MENU_H + ED_TOOLBAR_H + 1, ED_RIGHT_W, body_h, 0.18f, 0.18f, 0.23f, 1.0f);
|
||||
draw_quad(ctx, sw - ED_RIGHT_W - ED_SPLITTER, ED_MENU_H + ED_TOOLBAR_H + 1, ED_SPLITTER, body_h, 0.30f, 0.45f, 0.75f, 1.0f);
|
||||
/* bottom console */
|
||||
draw_quad(ctx, 0, sh - ED_BOTTOM_H - ED_SPLITTER, sw, ED_SPLITTER, 0.30f, 0.45f, 0.75f, 1.0f);
|
||||
draw_quad(ctx, 0, sh - ED_BOTTOM_H, sw, ED_BOTTOM_H, 0.16f, 0.16f, 0.21f, 1.0f);
|
||||
/* status bar */
|
||||
draw_quad(ctx, 0, sh - 22, sw, 22, 0.20f, 0.22f, 0.32f, 1.0f);
|
||||
}
|
||||
|
||||
static void draw_hierarchy(ID3D11DeviceContext* ctx, float sh) {
|
||||
(void)sh;
|
||||
int y = ED_MENU_H + ED_TOOLBAR_H + 28;
|
||||
draw_text(ctx, L"\u573a\u666f\u5c42\u7ea7", 12, y - 20, 0.5f, 0.75f, 1.0f, 1.0f);
|
||||
if (!g_scene) return;
|
||||
|
||||
for (int i = 1; i < g_scene->node_count; i++) {
|
||||
SceneNode* node = &g_scene->nodes[i];
|
||||
if (node->id < 0) continue;
|
||||
|
||||
int row_y = y + (i - 1) * 22;
|
||||
if (node == g_selected)
|
||||
draw_quad(ctx, 4, (float)row_y - 2, ED_LEFT_W - 8, 22, 0.25f, 0.38f, 0.65f, 1.0f);
|
||||
|
||||
wchar_t wn[64];
|
||||
int len = (int)strlen(node->name); if (len > 63) len = 63;
|
||||
for (int j = 0; j < len; j++) wn[j] = (wchar_t)node->name[j];
|
||||
wn[len] = 0;
|
||||
draw_text(ctx, wn, 16, row_y, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_inspector(ID3D11DeviceContext* ctx, float sw, float sh) {
|
||||
(void)sh;
|
||||
int x = (int)(sw - ED_RIGHT_W + 12);
|
||||
int y = ED_MENU_H + ED_TOOLBAR_H + 28;
|
||||
draw_text(ctx, L"\u5c5e\u6027", x, y - 20, 0.5f, 0.75f, 1.0f, 1.0f);
|
||||
if (!g_selected) {
|
||||
draw_text_a(ctx, "未选择对象", x, y, 0.7f, 0.7f, 0.75f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
int iy = y;
|
||||
snprintf(buf, sizeof(buf), "名称: %s", g_selected->name); draw_text_a(ctx, buf, x, iy, 1.0f, 1.0f, 1.0f, 1.0f); iy += 24;
|
||||
|
||||
float rx, ry, rz;
|
||||
quat_to_euler(&g_selected->rotation, &rx, &ry, &rz);
|
||||
snprintf(buf, sizeof(buf), "位置: %.2f %.2f %.2f", g_selected->position.x, g_selected->position.y, g_selected->position.z);
|
||||
draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 22;
|
||||
snprintf(buf, sizeof(buf), "旋转: %.1f %.1f %.1f", rx * 57.2958f, ry * 57.2958f, rz * 57.2958f);
|
||||
draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 22;
|
||||
snprintf(buf, sizeof(buf), "缩放: %.2f %.2f %.2f", g_selected->scale.x, g_selected->scale.y, g_selected->scale.z);
|
||||
draw_text_a(ctx, buf, x, iy, 0.85f, 0.85f, 0.88f, 1.0f); iy += 30;
|
||||
|
||||
draw_text_a(ctx, "WASD 平移 | QE 升降", x, iy, 0.6f, 0.7f, 0.85f, 1.0f); iy += 20;
|
||||
draw_text_a(ctx, "方向键 旋转 | +/- 缩放", x, iy, 0.6f, 0.7f, 0.85f, 1.0f);
|
||||
}
|
||||
|
||||
static void draw_console(ID3D11DeviceContext* ctx, float sh) {
|
||||
int y = (int)(sh - ED_BOTTOM_H + 24);
|
||||
draw_text(ctx, L"\u63a7\u5236\u53f0", 12, y - 18, 0.5f, 0.75f, 1.0f, 1.0f);
|
||||
int cy = y;
|
||||
for (int i = g_console_count - 1; i >= 0 && i >= g_console_count - 6; i--) {
|
||||
wchar_t wl[256];
|
||||
int len = (int)strlen(g_console[i]); if (len > 255) len = 255;
|
||||
for (int j = 0; j < len; j++) wl[j] = (wchar_t)g_console[i][j];
|
||||
wl[len] = 0;
|
||||
draw_text(ctx, wl, 12, cy, 0.75f, 0.75f, 0.80f, 1.0f);
|
||||
cy += 20;
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_ui(ID3D11DeviceContext* ctx, float sw, float sh) {
|
||||
ui_begin(ctx, sw, sh);
|
||||
draw_quad(ctx, 0, 0, sw, sh, 0.5f, 0, 0, 0.3f); /* debug overlay */
|
||||
draw_panel_bg(ctx, sw, sh);
|
||||
|
||||
/* title / menus */
|
||||
draw_text(ctx, L"Lity3D Engine Editor", 12, 7, 0.6f, 0.8f, 1.0f, 1.0f);
|
||||
const wchar_t* menus[] = {L"\u6587\u4ef6", L"\u7f16\u8f91", L"\u89c6\u56fe", L"\u6784\u5efa", L"\u5e2e\u52a9"};
|
||||
int mx = 160;
|
||||
for (int i = 0; i < 5; i++) { draw_text(ctx, menus[i], mx, 8, 0.9f, 0.9f, 0.92f, 1.0f); mx += 70; }
|
||||
|
||||
draw_hierarchy(ctx, sh);
|
||||
draw_inspector(ctx, sw, sh);
|
||||
draw_console(ctx, sh);
|
||||
|
||||
draw_text_a(ctx, g_status, 12, (int)(sh - 18), 0.65f, 0.65f, 0.70f, 1.0f);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Input / interaction */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void update_status(void) {
|
||||
if (g_selected) {
|
||||
snprintf(g_status, sizeof(g_status),
|
||||
"%s | pos(%.2f,%.2f,%.2f) | FOV %.0f | Esc quit | Ctrl+S save",
|
||||
g_selected->name,
|
||||
g_selected->position.x, g_selected->position.y, g_selected->position.z,
|
||||
g_camera.fov_y * 57.2958f);
|
||||
} else {
|
||||
snprintf(g_status, sizeof(g_status), "无选中对象 | FOV %.0f | Esc quit | Ctrl+S save", g_camera.fov_y * 57.2958f);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_hierarchy_click(int mx, int my) {
|
||||
float body_top = ED_MENU_H + ED_TOOLBAR_H + 1;
|
||||
float body_h = (float)g_gdev->height - ED_MENU_H - ED_TOOLBAR_H - ED_BOTTOM_H;
|
||||
if (mx < 0 || mx > ED_LEFT_W || my < body_top || my > body_top + body_h) return;
|
||||
|
||||
int list_y = ED_MENU_H + ED_TOOLBAR_H + 28;
|
||||
int idx = (my - list_y + 2) / 22 + 1;
|
||||
if (idx >= 1 && idx < g_scene->node_count) {
|
||||
SceneNode* node = &g_scene->nodes[idx];
|
||||
if (node->id >= 0) {
|
||||
g_selected = node;
|
||||
char buf[128]; snprintf(buf, sizeof(buf), "选中: %s", node->name);
|
||||
console_add(buf);
|
||||
update_status();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void on_mouse_move(Engine* engine, int x, int y) {
|
||||
(void)engine;
|
||||
g_mouse_x = x; g_mouse_y = y;
|
||||
|
||||
if (g_camera_drag && g_mouse_down[1]) {
|
||||
float dx = (float)(x - g_mouse_last_x);
|
||||
float dy = (float)(y - g_mouse_last_y);
|
||||
camera_rotate_yaw(&g_camera, dx * 0.005f);
|
||||
camera_rotate_pitch(&g_camera, dy * 0.005f);
|
||||
g_mouse_last_x = x; g_mouse_last_y = y;
|
||||
} else if (g_mouse_down[1]) {
|
||||
g_camera_drag = 1;
|
||||
g_mouse_last_x = x; g_mouse_last_y = y;
|
||||
} else {
|
||||
g_camera_drag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_mouse_button(Engine* engine, int button, int pressed) {
|
||||
(void)engine;
|
||||
if (button >= 0 && button < 3) g_mouse_down[button] = pressed;
|
||||
|
||||
if (button == 0 && pressed) {
|
||||
process_hierarchy_click(g_mouse_x, g_mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
if (key == VK_ESCAPE) { engine_request_quit(engine); return; }
|
||||
|
||||
if (GetAsyncKeyState(VK_CONTROL) & 0x8000) {
|
||||
if (key == 'S' || key == 's') {
|
||||
if (scene_save(g_scene, "scene.txt")) {
|
||||
console_add("已保存 scene.txt");
|
||||
} else {
|
||||
console_add("保存 scene.txt 失败");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (key == 'O' || key == 'o') {
|
||||
Scene* new_scene = scene_load("scene.txt", g_gdev->device, (Shader*)asset_data(g_shader_asset));
|
||||
if (new_scene) {
|
||||
scene_destroy_renderers(g_scene);
|
||||
scene_destroy(g_scene);
|
||||
free(g_scene);
|
||||
g_scene = new_scene;
|
||||
g_selected = NULL;
|
||||
console_add("已加载 scene.txt");
|
||||
} else {
|
||||
console_add("加载 scene.txt 失败");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_selected) return;
|
||||
|
||||
float speed = 0.1f;
|
||||
if (GetAsyncKeyState(VK_SHIFT) & 0x8000) speed = 0.5f;
|
||||
|
||||
Vec3 pos = g_selected->position;
|
||||
switch (key) {
|
||||
case 'W': case 'w': pos.z += speed; break;
|
||||
case 'S': case 's': pos.z -= speed; break;
|
||||
case 'A': case 'a': pos.x -= speed; break;
|
||||
case 'D': case 'd': pos.x += speed; break;
|
||||
case 'Q': case 'q': pos.y += speed; break;
|
||||
case 'E': case 'e': pos.y -= speed; break;
|
||||
default: break;
|
||||
}
|
||||
if (pos.x != g_selected->position.x || pos.y != g_selected->position.y || pos.z != g_selected->position.z) {
|
||||
scene_set_position(g_selected, pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
float rx, ry, rz;
|
||||
quat_to_euler(&g_selected->rotation, &rx, &ry, &rz);
|
||||
int rot_changed = 0;
|
||||
switch (key) {
|
||||
case VK_LEFT: ry -= 0.05f; rot_changed = 1; break;
|
||||
case VK_RIGHT: ry += 0.05f; rot_changed = 1; break;
|
||||
case VK_UP: rx -= 0.05f; rot_changed = 1; break;
|
||||
case VK_DOWN: rx += 0.05f; rot_changed = 1; break;
|
||||
case VK_PRIOR: rz += 0.05f; rot_changed = 1; break; /* PageUp */
|
||||
case VK_NEXT: rz -= 0.05f; rot_changed = 1; break; /* PageDown */
|
||||
default: break;
|
||||
}
|
||||
if (rot_changed) scene_set_rotation_euler(g_selected, rx, ry, rz);
|
||||
|
||||
Vec3 scale = g_selected->scale;
|
||||
int scale_changed = 0;
|
||||
switch (key) {
|
||||
case VK_ADD: scale.x += 0.1f; scale.y += 0.1f; scale.z += 0.1f; scale_changed = 1; break;
|
||||
case VK_SUBTRACT: scale.x -= 0.1f; scale.y -= 0.1f; scale.z -= 0.1f; scale_changed = 1; break;
|
||||
default: break;
|
||||
}
|
||||
if (scale_changed) scene_set_scale(g_selected, scale.x, scale.y, scale.z);
|
||||
|
||||
update_status();
|
||||
}
|
||||
|
||||
static void on_resize(Engine* engine, int width, int height) {
|
||||
(void)engine;
|
||||
if (width > 0 && height > 0) {
|
||||
renderer_resize(g_renderer, width, height);
|
||||
g_camera.aspect = (float)width / (float)height;
|
||||
g_camera.dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Render callback */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
static void on_render(Engine* engine) {
|
||||
(void)engine;
|
||||
if (!g_renderer || !g_gdev) return;
|
||||
|
||||
renderer_set_view(g_renderer, camera_get_view(&g_camera));
|
||||
renderer_set_projection(g_renderer, camera_get_projection(&g_camera));
|
||||
|
||||
renderer_begin_frame(g_renderer);
|
||||
if (g_scene) {
|
||||
scene_update(g_scene);
|
||||
scene_render(g_scene, g_renderer);
|
||||
}
|
||||
|
||||
draw_ui(g_gdev->context, (float)g_gdev->width, (float)g_gdev->height);
|
||||
|
||||
renderer_end_frame(g_renderer);
|
||||
|
||||
if (engine->frame_count == 60) {
|
||||
graphics_device_save_screenshot(g_gdev, "editor_screenshot.bmp");
|
||||
console_add("已保存 editor_screenshot.bmp");
|
||||
}
|
||||
}
|
||||
|
||||
static void on_update(Engine* engine, double dt) {
|
||||
(void)engine; (void)dt;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Main */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) {
|
||||
(void)hI; (void)hP; (void)nS;
|
||||
logger_init("engine.log");
|
||||
LOG_INFO("=== Lity3D Engine Editor ===");
|
||||
|
||||
EngineConfig cfg = engine_default_config();
|
||||
cfg.app_name = "Lity3D Engine Editor";
|
||||
cfg.window_width = 1440;
|
||||
cfg.window_height = 900;
|
||||
cfg.vsync = 1;
|
||||
|
||||
g_engine = engine_create();
|
||||
if (!engine_init(g_engine, &cfg)) {
|
||||
LOG_FATAL("Engine init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_gdev = engine_get_graphics_device(g_engine);
|
||||
g_renderer = engine_get_renderer(g_engine);
|
||||
|
||||
g_assets = asset_manager_create();
|
||||
g_shader_asset = asset_manager_load_shader(g_assets, g_gdev->device, NULL, NULL);
|
||||
if (!g_shader_asset) {
|
||||
LOG_FATAL("Shader load failed");
|
||||
return -1;
|
||||
}
|
||||
Shader* default_shader = (Shader*)asset_data(g_shader_asset);
|
||||
|
||||
g_scene = scene_load("scene.txt", g_gdev->device, default_shader);
|
||||
if (!g_scene) {
|
||||
LOG_INFO("Creating default editor scene");
|
||||
g_scene = create_default_editor_scene(g_assets, g_gdev->device, default_shader);
|
||||
scene_save(g_scene, "scene.txt");
|
||||
}
|
||||
|
||||
float aspect = (float)cfg.window_width / cfg.window_height;
|
||||
g_camera = camera_perspective(1.0472f, aspect, 0.1f, 100.0f);
|
||||
g_camera.position = (Vec3){0, 1.5f, -5.0f};
|
||||
g_camera.target = (Vec3){0, 0, 0};
|
||||
g_camera.dirty = 1;
|
||||
|
||||
g_atlas_ok = glyph_atlas_init(&g_atlas, g_gdev->device);
|
||||
if (!g_atlas_ok) LOG_WARN("GlyphAtlas init failed");
|
||||
|
||||
create_ui_states(g_gdev->device);
|
||||
if (!compile_ui_shaders(g_gdev->device)) {
|
||||
LOG_FATAL("UI shader compile failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
console_add("Lity3D Engine Editor ready");
|
||||
console_add("Ctrl+S 保存 | Ctrl+O 加载 | Esc 退出");
|
||||
console_add("左键点选层级,右键拖拽旋转视角");
|
||||
update_status();
|
||||
|
||||
engine_set_update_callback(g_engine, on_update);
|
||||
engine_set_render_callback(g_engine, on_render);
|
||||
engine_set_key_callback(g_engine, on_key);
|
||||
engine_set_resize_callback(g_engine, on_resize);
|
||||
engine_set_mouse_move_callback(g_engine, on_mouse_move);
|
||||
engine_set_mouse_button_callback(g_engine, on_mouse_button);
|
||||
|
||||
engine_run(g_engine);
|
||||
|
||||
if (g_scene) {
|
||||
scene_destroy_renderers(g_scene);
|
||||
scene_destroy(g_scene);
|
||||
free(g_scene);
|
||||
}
|
||||
asset_manager_destroy(g_assets);
|
||||
|
||||
if (g_ui_sampler) g_ui_sampler->lpVtbl->Release(g_ui_sampler);
|
||||
if (g_ui_blend) g_ui_blend->lpVtbl->Release(g_ui_blend);
|
||||
if (g_ui_raster) g_ui_raster->lpVtbl->Release(g_ui_raster);
|
||||
if (g_ui_depth) g_ui_depth->lpVtbl->Release(g_ui_depth);
|
||||
if (g_ui_cb) g_ui_cb->lpVtbl->Release(g_ui_cb);
|
||||
if (g_ui_ps) g_ui_ps->lpVtbl->Release(g_ui_ps);
|
||||
if (g_ui_vs) g_ui_vs->lpVtbl->Release(g_ui_vs);
|
||||
if (g_ui_layout) g_ui_layout->lpVtbl->Release(g_ui_layout);
|
||||
if (g_atlas_ok) glyph_atlas_destroy(&g_atlas);
|
||||
|
||||
engine_shutdown(g_engine);
|
||||
logger_shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
|
||||
static ID3D11Device* g_dev = NULL;
|
||||
static ID3D11DeviceContext* g_ctx = NULL;
|
||||
static IDXGISwapChain* g_sc = NULL;
|
||||
static ID3D11RenderTargetView* g_rtv = NULL;
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
|
||||
static float cam_x = 0, cam_z = 0;
|
||||
static int key_w = 0, key_s = 0, key_a = 0, key_d = 0;
|
||||
static int key_left = 0, key_right = 0;
|
||||
static int sel = 0;
|
||||
|
||||
static void Init(HWND h) {
|
||||
HRESULT hr;
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = h;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
|
||||
D3D_FEATURE_LEVEL got;
|
||||
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &fl, 1,
|
||||
D3D11_SDK_VERSION, &sd, &g_sc, &g_dev, &got, &g_ctx);
|
||||
if (FAILED(hr)) { return; }
|
||||
ID3D11Texture2D* bb = NULL;
|
||||
hr = g_sc->lpVtbl->GetBuffer(g_sc, 0, &IID_ID3D11Texture2D, (void**)&bb);
|
||||
if (FAILED(hr) || !bb) { return; }
|
||||
hr = g_dev->lpVtbl->CreateRenderTargetView(g_dev, (ID3D11Resource*)bb, NULL, &g_rtv);
|
||||
bb->lpVtbl->Release(bb);
|
||||
if (FAILED(hr)) { return; }
|
||||
const char* vs_src =
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"struct O{float4 p:SV_POSITION;float4 c:COLOR;};"
|
||||
"O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.c=i.c;return o;}";
|
||||
const char* ps_src =
|
||||
"float4 main(float4 pos:SV_POSITION, float4 col:COLOR):SV_Target{return col;}";
|
||||
ID3DBlob *b1 = NULL, *b2 = NULL, *e1 = NULL, *e2 = NULL;
|
||||
D3DCompile(vs_src, (UINT)strlen(vs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &b1, &e1);
|
||||
if (e1) { e1->lpVtbl->Release(e1); e1 = NULL; }
|
||||
D3DCompile(ps_src, (UINT)strlen(ps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &b2, &e2);
|
||||
if (e2) { e2->lpVtbl->Release(e2); e2 = NULL; }
|
||||
if (!b1 || !b2) { return; }
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), NULL, &g_vs);
|
||||
g_dev->lpVtbl->CreatePixelShader(g_dev, b2->lpVtbl->GetBufferPointer(b2), b2->lpVtbl->GetBufferSize(b2), NULL, &g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];
|
||||
memset(el, 0, sizeof(el));
|
||||
el[0].SemanticName = "POSITION"; el[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[1].SemanticName = "NORMAL"; el[1].AlignedByteOffset = 12; el[1].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[2].SemanticName = "TEXCOORD"; el[2].AlignedByteOffset = 24; el[2].Format = DXGI_FORMAT_R32G32_FLOAT; el[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[3].SemanticName = "COLOR"; el[3].AlignedByteOffset = 32; el[3].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; el[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev, el, 4, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), &g_il);
|
||||
b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;
|
||||
memset(&cbd, 0, sizeof(cbd));
|
||||
cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
g_dev->lpVtbl->CreateBuffer(g_dev, &cbd, NULL, &g_cb);
|
||||
}
|
||||
|
||||
static void DrawCube(float cx, float cy, float cz, float s, float cr, float cg, float cb2) {
|
||||
V3D v[24];
|
||||
float f[6][4][3] = {
|
||||
{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},
|
||||
{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},
|
||||
{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},
|
||||
{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},
|
||||
{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},
|
||||
{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}
|
||||
};
|
||||
float nm[6][3] = {{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for (int fi = 0; fi < 6; fi++)
|
||||
for (int vi = 0; vi < 4; vi++) {
|
||||
int i = fi * 4 + vi;
|
||||
v[i].p[0] = f[fi][vi][0] * s + cx;
|
||||
v[i].p[1] = f[fi][vi][1] * s + cy;
|
||||
v[i].p[2] = f[fi][vi][2] * s + cz;
|
||||
v[i].n[0] = nm[fi][0]; v[i].n[1] = nm[fi][1]; v[i].n[2] = nm[fi][2];
|
||||
v[i].c[0] = cr; v[i].c[1] = cg; v[i].c[2] = cb2; v[i].c[3] = 1;
|
||||
}
|
||||
uint32_t ix[36];
|
||||
for (int fi = 0; fi < 6; fi++) {
|
||||
int b = fi * 4;
|
||||
ix[fi*6]=b; ix[fi*6+1]=b+1; ix[fi*6+2]=b+2; ix[fi*6+3]=b; ix[fi*6+4]=b+2; ix[fi*6+5]=b+3;
|
||||
}
|
||||
ID3D11Buffer *vb = NULL, *ib = NULL;
|
||||
D3D11_BUFFER_DESC bd; D3D11_SUBRESOURCE_DATA sd;
|
||||
memset(&bd, 0, sizeof(bd)); memset(&sd, 0, sizeof(sd));
|
||||
bd.ByteWidth = sizeof(V3D) * 24; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = v; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &vb);
|
||||
bd.ByteWidth = sizeof(uint32_t) * 36; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = ix; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &ib);
|
||||
UINT s2 = sizeof(V3D), o = 0;
|
||||
g_ctx->lpVtbl->IASetVertexBuffers(g_ctx, 0, 1, &vb, &s2, &o);
|
||||
g_ctx->lpVtbl->IASetIndexBuffer(g_ctx, ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
g_ctx->lpVtbl->DrawIndexed(g_ctx, 36, 0, 0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void Frame(void) {
|
||||
float dt = 0.016f, spd = 3.0f * dt;
|
||||
if (key_w) cam_z += spd; if (key_s) cam_z -= spd;
|
||||
if (key_a) cam_x -= spd; if (key_d) cam_x += spd;
|
||||
if (key_left) sel = (sel + 3) % 4;
|
||||
if (key_right) sel = (sel + 1) % 4;
|
||||
|
||||
float fov = 1.0f / tanf(0.4f), asp = 1280.0f / 720.0f;
|
||||
float mvp[16]; memset(mvp, 0, sizeof(mvp));
|
||||
mvp[0] = fov / asp; mvp[5] = -fov; mvp[10] = 1; mvp[11] = -1; mvp[14] = 0.1f; mvp[15] = 1;
|
||||
float m2[16]; memcpy(m2, mvp, 64);
|
||||
for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { float t = m2[i*4+j]; m2[i*4+j] = m2[j*4+i]; m2[j*4+i] = t; }
|
||||
|
||||
float cl[4] = {.15f, .18f, .25f, 1};
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx, 1, &g_rtv, NULL);
|
||||
g_ctx->lpVtbl->ClearRenderTargetView(g_ctx, g_rtv, cl);
|
||||
D3D11_VIEWPORT vp; memset(&vp, 0, sizeof(vp));
|
||||
vp.Width = 1280; vp.Height = 720; vp.MaxDepth = 1;
|
||||
g_ctx->lpVtbl->RSSetViewports(g_ctx, 1, &vp);
|
||||
D3D11_RASTERIZER_DESC rd; memset(&rd, 0, sizeof(rd));
|
||||
rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs = NULL;
|
||||
g_dev->lpVtbl->CreateRasterizerState(g_dev, &rd, &rs);
|
||||
g_ctx->lpVtbl->RSSetState(g_ctx, rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds; memset(&ds, 0, sizeof(ds));
|
||||
ds.DepthEnable = FALSE;
|
||||
ID3D11DepthStencilState* dss = NULL;
|
||||
g_dev->lpVtbl->CreateDepthStencilState(g_dev, &ds, &dss);
|
||||
g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx, dss, 0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
g_ctx->lpVtbl->VSSetShader(g_ctx, g_vs, NULL, 0);
|
||||
g_ctx->lpVtbl->PSSetShader(g_ctx, g_ps, NULL, 0);
|
||||
g_ctx->lpVtbl->IASetInputLayout(g_ctx, g_il);
|
||||
g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx, 0, 1, &g_cb);
|
||||
g_ctx->lpVtbl->UpdateSubresource(g_ctx, (ID3D11Resource*)g_cb, 0, NULL, m2, 0, 0);
|
||||
|
||||
float colors[4][3] = {{1,.3f,.3f},{.3f,1,.3f},{.3f,.3f,1},{.8f,.8f,.2f}};
|
||||
float sizes[4] = {0.3f, 0.25f, 0.2f, 0.35f};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float cr = colors[i][0], cg = colors[i][1], cb = colors[i][2];
|
||||
if (i == sel) { cr = 1; cg = 1; cb = 1; }
|
||||
DrawCube(-0.8f + i * 0.6f - cam_x, 0, 1.5f - cam_z, sizes[i], cr, cg, cb);
|
||||
}
|
||||
|
||||
if (rs) rs->lpVtbl->Release(rs);
|
||||
if (dss) dss->lpVtbl->Release(dss);
|
||||
g_sc->lpVtbl->Present(g_sc, 1, 0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h, UINT m, WPARAM w, LPARAM l) {
|
||||
switch (m) {
|
||||
case WM_KEYDOWN:
|
||||
switch (w) {
|
||||
case 'W': key_w = 1; break; case 'S': key_s = 1; break;
|
||||
case 'A': key_a = 1; break; case 'D': key_d = 1; break;
|
||||
case VK_LEFT: key_left = 1; break; case VK_RIGHT: key_right = 1; break;
|
||||
case '1': sel = 0; break; case '2': sel = 1; break;
|
||||
case '3': sel = 2; break; case '4': sel = 3; break;
|
||||
case VK_ESCAPE: PostQuitMessage(0); break;
|
||||
}
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
switch (w) {
|
||||
case 'W': key_w = 0; break; case 'S': key_s = 0; break;
|
||||
case 'A': key_a = 0; break; case 'D': key_d = 0; break;
|
||||
case VK_LEFT: key_left = 0; break; case VK_RIGHT: key_right = 0; break;
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY: PostQuitMessage(0); return 0;
|
||||
}
|
||||
return DefWindowProcW(h, m, w, l);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR nC, int nS) {
|
||||
(void)hP; (void)nC; (void)nS;
|
||||
WNDCLASSEXW wc;
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.style = CS_CLASSDC;
|
||||
wc.lpfnWndProc = WP;
|
||||
wc.hInstance = hI;
|
||||
wc.lpszClassName = L"game_test_cls";
|
||||
RegisterClassExW(&wc);
|
||||
HWND hwnd = CreateWindowW(L"game_test_cls", L"lity3d Game Test", WS_OVERLAPPEDWINDOW,
|
||||
100, 100, 1280, 720, NULL, NULL, hI, NULL);
|
||||
if (!hwnd) { MessageBoxA(NULL, "CreateWindow failed", "Error", MB_OK); return -1; }
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
Init(hwnd);
|
||||
MSG msg;
|
||||
while (1) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg); DispatchMessage(&msg);
|
||||
if (msg.message == WM_QUIT) goto done;
|
||||
}
|
||||
Frame();
|
||||
}
|
||||
done:
|
||||
if (g_cb) g_cb->lpVtbl->Release(g_cb);
|
||||
if (g_il) g_il->lpVtbl->Release(g_il);
|
||||
if (g_vs) g_vs->lpVtbl->Release(g_vs);
|
||||
if (g_ps) g_ps->lpVtbl->Release(g_ps);
|
||||
if (g_rtv) g_rtv->lpVtbl->Release(g_rtv);
|
||||
if (g_sc) g_sc->lpVtbl->Release(g_sc);
|
||||
if (g_ctx) g_ctx->lpVtbl->Release(g_ctx);
|
||||
if (g_dev) g_dev->lpVtbl->Release(g_dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
static float cam_x=0, cam_z=2, cam_yaw=0;
|
||||
static float mx=0, my=0;
|
||||
static int keys[256]={0};
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float z, float s, float r, float g, float b) {
|
||||
V v[4]={{{x-s,y-s,z},{0,0,-1},{0,0},{r,g,b,1}},{{x+s,y-s,z},{0,0,-1},{1,0},{r,g,b,1}},
|
||||
{{x+s,y+s,z},{0,0,-1},{1,1},{r,g,b,1}},{{x-s,y+s,z},{0,0,-1},{0,1},{r,g,b,1}}};
|
||||
uint32_t idx[6]={0,1,2,0,2,3};
|
||||
ID3D11Buffer *vb=NULL,*ib=NULL; D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER; sd.pSysMem=idx;
|
||||
g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V),o=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if(!g_dev) return;
|
||||
ID3D11DeviceContext* ctx=g_dev->context;
|
||||
float dt=(float)engine->delta_time, sp=3.0f*dt;
|
||||
float fx=-sinf(cam_yaw),fz=-cosf(cam_yaw),rx=cosf(cam_yaw),rz=-sinf(cam_yaw);
|
||||
if(keys['W']){cam_x+=fx*sp;cam_z+=fz*sp;}
|
||||
if(keys['S']){cam_x-=fx*sp;cam_z-=fz*sp;}
|
||||
if(keys['A']){cam_x-=rx*sp;cam_z-=rz*sp;}
|
||||
if(keys['D']){cam_x+=rx*sp;cam_z+=rz*sp;}
|
||||
|
||||
float sw=(float)g_dev->width,sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f),asp=sw/sh;
|
||||
float mvp[16]={0}; mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
Mat4 pm,pt;memcpy(&pm,mvp,sizeof(Mat4));mat4_transpose(&pm,&pt);
|
||||
|
||||
graphics_device_clear(g_dev,0.12f,0.14f,0.18f,1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState*rs=NULL;g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState*dss=NULL;g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->lpVtbl->VSSetShader(ctx,g_vs,NULL,0);ctx->lpVtbl->PSSetShader(ctx,g_ps,NULL,0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx,g_il);ctx->lpVtbl->VSSetConstantBuffers(ctx,0,1,&g_cb);
|
||||
ctx->lpVtbl->UpdateSubresource(ctx,(ID3D11Resource*)g_cb,0,NULL,&pt,0,0);
|
||||
for(int x=-5;x<=5;x++)for(int z=-5;z<=5;z++){float c=((x+z)%2==0)?.4f:.3f;draw_quad(ctx,(float)x,(float)z,0.5f,0.5f,c,c,c);}
|
||||
draw_quad(ctx,0,0,0.5f,0.4f,1,0.3f,0.3f);draw_quad(ctx,2,0,0.5f,0.3f,.3f,1,.3f);draw_quad(ctx,-2,0,0.5f,0.3f,.3f,.3f,1);draw_quad(ctx,0,2,0.5f,0.5f,.8f,.8f,.2f);
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
static void on_key(Engine*e,int k){if(k>=0&&k<256)keys[k]=1;if(k==VK_ESCAPE)engine_request_quit(e);}
|
||||
static void on_mouse_move(int x,int y){cam_yaw+=(x-mx)*0.003f;mx=(float)x;my=(float)y;}
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){
|
||||
EngineConfig cfg=engine_default_config();cfg.app_name="lity3d Input Test";
|
||||
Engine*e=engine_create();if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
ID3DBlob*b1=NULL,*b2=NULL,*er=NULL;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
const char*ps="struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};float4 main(O i){return i.c;}";
|
||||
D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&er);if(er){er->lpVtbl->Release(er);er=NULL;}
|
||||
D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&er);if(er){er->lpVtbl->Release(er);er=NULL;}
|
||||
ID3D11Device*dev=g_dev->device;
|
||||
dev->lpVtbl->CreateVertexShader(dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);
|
||||
dev->lpVtbl->CreatePixelShader(dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC il[]={{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0}};
|
||||
dev->lpVtbl->CreateInputLayout(dev,il,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd={};cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;dev->lpVtbl->CreateBuffer(dev,&cbd,NULL,&g_cb);
|
||||
window_set_key_callback(e->window,on_key);window_set_mouse_move_callback(e->window,on_mouse_move);
|
||||
engine_set_render_callback(e,on_render);engine_run(e);
|
||||
if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_il)g_il->lpVtbl->Release(g_il);if(g_cb)g_cb->lpVtbl->Release(g_cb);
|
||||
graphics_device_destroy(g_dev);engine_shutdown(e);return 0;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// light_test.c - 光照系统测试(基?raw3d_test 已验证模式)
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Rendering/lighting.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Light* g_sun = NULL;
|
||||
static float g_time = 0;
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
// 编译带光照的着色器
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
|
||||
static const char* vs_src =
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};"
|
||||
"O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
static const char* ps_src =
|
||||
"cbuffer Light:register(b1){float3 lightDir;float pad1;float3 lightColor;float intensity;float3 ambColor;float pad2;};"
|
||||
"struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};"
|
||||
"float4 main(O i):SV_TARGET{"
|
||||
"float3 n=normalize(i.n);"
|
||||
"float diff=max(dot(n,-normalize(lightDir)),0.0);"
|
||||
"float3 col=i.c.rgb*(ambColor+lightColor*diff*intensity);"
|
||||
"return float4(col,1.0);}";
|
||||
|
||||
static void InitShaders() {
|
||||
ID3DBlob *b1=NULL,*b2=NULL,*e=NULL;
|
||||
D3DCompile(vs_src,(UINT)strlen(vs_src),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);
|
||||
if(e){e->lpVtbl->Release(e);e=NULL;}
|
||||
D3DCompile(ps_src,(UINT)strlen(ps_src),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);
|
||||
if(e){e->lpVtbl->Release(e);e=NULL;}
|
||||
if(!b1||!b2) return;
|
||||
ID3D11Device* dev = g_dev->device;
|
||||
dev->lpVtbl->CreateVertexShader(dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);
|
||||
dev->lpVtbl->CreatePixelShader(dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC il[]={
|
||||
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
};
|
||||
dev->lpVtbl->CreateInputLayout(dev,il,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);
|
||||
b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd={}; cbd.ByteWidth=256; cbd.Usage=D3D11_USAGE_DEFAULT;
|
||||
cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
|
||||
dev->lpVtbl->CreateBuffer(dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void draw_lit_cube(ID3D11DeviceContext* ctx, ID3D11Device* dev, float cx, float cy, float cz, float s, float cr, float cg, float cb) {
|
||||
V v[24];
|
||||
float f[6][4][3]={{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},
|
||||
{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},
|
||||
{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}};
|
||||
float nm[6][3]={{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for(int fi=0;fi<6;fi++) for(int vi=0;vi<4;vi++){
|
||||
int i=fi*4+vi;
|
||||
v[i].p[0]=f[fi][vi][0]*s+cx; v[i].p[1]=f[fi][vi][1]*s+cy; v[i].p[2]=f[fi][vi][2]*s+cz;
|
||||
v[i].n[0]=nm[fi][0]; v[i].n[1]=nm[fi][1]; v[i].n[2]=nm[fi][2];
|
||||
v[i].c[0]=cr; v[i].c[1]=cg; v[i].c[2]=cb; v[i].c[3]=1;
|
||||
}
|
||||
uint32_t idx[36]; for(int fi=0;fi<6;fi++){int b=fi*4;idx[fi*6]=b;idx[fi*6+1]=b+1;idx[fi*6+2]=b+2;idx[fi*6+3]=b;idx[fi*6+4]=b+2;idx[fi*6+5]=b+3;}
|
||||
ID3D11Buffer *vb,*ib;D3D11_BUFFER_DESC bd={};D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*24;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;sd.pSysMem=v;
|
||||
dev->lpVtbl->CreateBuffer(dev,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*36;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;sd.pSysMem=idx;
|
||||
dev->lpVtbl->CreateBuffer(dev,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V),o=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,36,0,0);
|
||||
ib->lpVtbl->Release(ib);vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if(!g_dev) return;
|
||||
ID3D11DeviceContext* ctx=g_dev->context;
|
||||
g_time+=0.016f;
|
||||
|
||||
float sw=(float)g_dev->width,sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f),asp=sw/sh;
|
||||
float mvp[16]={0}; mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
Mat4 pm,pt;memcpy(&pm,mvp,sizeof(Mat4));mat4_transpose(&pm,&pt);
|
||||
|
||||
graphics_device_clear(g_dev,0.15f,0.18f,0.25f,1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState*rs=NULL;g_dev->device->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState*dss=NULL;g_dev->device->lpVtbl->CreateDepthStencilState(g_dev,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绑定光照 shader
|
||||
ctx->lpVtbl->VSSetShader(ctx,g_vs,NULL,0);
|
||||
ctx->lpVtbl->PSSetShader(ctx,g_ps,NULL,0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx,g_il);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx,0,1,&g_cb);
|
||||
ctx->lpVtbl->UpdateSubresource(ctx,(ID3D11Resource*)g_cb,0,NULL,&pt,0,0);
|
||||
|
||||
// 更新光照 CB
|
||||
float light_data[16]={0};
|
||||
light_data[0]=g_sun->direction[0];light_data[1]=g_sun->direction[1];light_data[2]=g_sun->direction[2];
|
||||
light_data[4]=g_sun->color[0];light_data[5]=g_sun->color[1];light_data[6]=g_sun->color[2];
|
||||
light_data[7]=g_sun->intensity;
|
||||
light_data[8]=0.15f;light_data[9]=0.15f;light_data[10]=0.2f;
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx,1,1,&g_cb);
|
||||
|
||||
draw_lit_cube(ctx,g_dev, 0,0,0.5f, 0.3f, 1,0.3f,0.3f);
|
||||
draw_lit_cube(ctx,g_dev,-0.8f,0,0.7f, 0.2f, 0.3f,1,0.3f);
|
||||
draw_lit_cube(ctx,g_dev, 0.8f,0.3f,0.3f, 0.15f, 0.3f,0.3f,1);
|
||||
draw_lit_cube(ctx,g_dev, 0,-0.2f,0.8f, 0.4f, 0.8f,0.8f,0.2f);
|
||||
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine*e,int k){if(k==VK_ESCAPE)engine_request_quit(e);}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){
|
||||
EngineConfig cfg=engine_default_config();cfg.app_name="lity3d Light Test";
|
||||
Engine*e=engine_create();if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
InitShaders();
|
||||
g_sun=light_create_dir(1.0f,0.95f,0.8f,1.2f, -0.5f,-1.0f,-0.3f);
|
||||
engine_set_render_callback(e,on_render);engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
light_destroy(g_sun);graphics_device_destroy(g_dev);engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
// ============================================================================
|
||||
// ly_interpreter.c - .ly 积木语言独立解释器
|
||||
// 直接解析 .ly 格式,不依赖引擎 VisualScript 框架
|
||||
// 用法: ly_interpreter.exe <script.ly>
|
||||
// ============================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// === 数据结构 ===
|
||||
typedef union { double num; char str[256]; int bool_val; } Value;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
char name[64];
|
||||
float x, y;
|
||||
char data[256];
|
||||
int color;
|
||||
Value inputs[8];
|
||||
int input_count;
|
||||
Value outputs[4];
|
||||
int output_count;
|
||||
} Block;
|
||||
|
||||
typedef struct {
|
||||
int from_block, from_slot;
|
||||
int to_block, to_slot;
|
||||
} Wire;
|
||||
|
||||
#define MAX_BLOCKS 256
|
||||
#define MAX_WIRES 256
|
||||
|
||||
static Block g_blocks[MAX_BLOCKS];
|
||||
static int g_block_count = 0;
|
||||
static Wire g_wires[MAX_WIRES];
|
||||
static int g_wire_count = 0;
|
||||
|
||||
// === 解析 ===
|
||||
|
||||
static void trim(char* s) {
|
||||
char* p = s;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (p != s) memmove(s, p, strlen(p) + 1);
|
||||
int len = strlen(s);
|
||||
while (len > 0 && (s[len-1] == '\n' || s[len-1] == '\r' || s[len-1] == ' ')) s[--len] = 0;
|
||||
}
|
||||
|
||||
static int parse_ly(const char* path) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) { fprintf(stderr, "Cannot open %s\n", path); return 0; }
|
||||
|
||||
char line[1024];
|
||||
int section = 0; // 0=none, 1=block, 2=wire
|
||||
int cur_bid = -1;
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
trim(line);
|
||||
if (line[0] == '#' || line[0] == 0) continue;
|
||||
|
||||
if (strcmp(line, "[B]") == 0 || strcmp(line, "[Block]") == 0) { section = 1; cur_bid = -1; continue; }
|
||||
if (strcmp(line, "[W]") == 0 || strcmp(line, "[Wire]") == 0) { section = 2; continue; }
|
||||
if (line[0] == '[') { section = 0; continue; }
|
||||
|
||||
if (section == 1) {
|
||||
char* eq = strchr(line, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0; char* key = line; char* val = eq + 1;
|
||||
|
||||
if (strcmp(key, "id") == 0) {
|
||||
cur_bid = g_block_count;
|
||||
memset(&g_blocks[cur_bid], 0, sizeof(Block));
|
||||
g_blocks[cur_bid].id = atoi(val);
|
||||
g_block_count++;
|
||||
} else if (cur_bid >= 0) {
|
||||
if (strcmp(key, "name") == 0) strncpy(g_blocks[cur_bid].name, val, 63);
|
||||
else if (strcmp(key, "p") == 0 || strcmp(key, "pos") == 0) sscanf(val, "%f,%f", &g_blocks[cur_bid].x, &g_blocks[cur_bid].y);
|
||||
else if (strcmp(key, "d") == 0 || strcmp(key, "data") == 0) strncpy(g_blocks[cur_bid].data, val, 255);
|
||||
else if (strcmp(key, "c") == 0 || strcmp(key, "color") == 0) g_blocks[cur_bid].color = atoi(val);
|
||||
}
|
||||
} else if (section == 2) {
|
||||
Wire* w = &g_wires[g_wire_count];
|
||||
char* eq = strchr(line, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0; char* key = line; char* val = eq + 1;
|
||||
|
||||
if (strcmp(key, "a") == 0 || strcmp(key, "from") == 0) {
|
||||
w->from_block = atoi(val) / 10000;
|
||||
w->from_slot = atoi(val) % 10000;
|
||||
} else if (strcmp(key, "b") == 0 || strcmp(key, "to") == 0) {
|
||||
w->to_block = atoi(val) / 10000;
|
||||
w->to_slot = atoi(val) % 10000;
|
||||
if (w->from_block > 0) g_wire_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
printf("Parsed: %d blocks, %d wires\n", g_block_count, g_wire_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// === 查找 ===
|
||||
|
||||
static Block* find_block(int id) {
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
if (g_blocks[i].id == id) return &g_blocks[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 找到从某个 block 的 output_slot 出发,连接到的下一个 block
|
||||
static Block* follow_wire(int from_id, int from_slot) {
|
||||
for (int i = 0; i < g_wire_count; i++) {
|
||||
if (g_wires[i].from_block == from_id && g_wires[i].from_slot == from_slot)
|
||||
return find_block(g_wires[i].to_block);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 获取连接到某个 block input_slot 的值
|
||||
static Value get_input_value(int block_id, int slot) {
|
||||
for (int i = 0; i < g_wire_count; i++) {
|
||||
if (g_wires[i].to_block == block_id && g_wires[i].to_slot == slot) {
|
||||
Block* src = find_block(g_wires[i].from_block);
|
||||
if (src && src->output_count > g_wires[i].from_slot)
|
||||
return src->outputs[g_wires[i].from_slot];
|
||||
}
|
||||
}
|
||||
Value v; v.num = 0; return v;
|
||||
}
|
||||
|
||||
// === 解释执行 ===
|
||||
|
||||
static int g_variables[64]; // 简单变量存储
|
||||
static char g_var_names[64][64];
|
||||
static int g_var_count = 0;
|
||||
|
||||
static int get_var(const char* name) {
|
||||
for (int i = 0; i < g_var_count; i++)
|
||||
if (strcmp(g_var_names[i], name) == 0) return g_variables[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_var(const char* name, int val) {
|
||||
for (int i = 0; i < g_var_count; i++)
|
||||
if (strcmp(g_var_names[i], name) == 0) { g_variables[i] = val; return; }
|
||||
if (g_var_count < 64) { strncpy(g_var_names[g_var_count], name, 63); g_variables[g_var_count++] = val; }
|
||||
}
|
||||
|
||||
static void execute(Block* block, int depth);
|
||||
|
||||
static void execute_block(Block* b, int depth) {
|
||||
if (!b) return;
|
||||
if (depth > 100) { printf("Stack overflow!\n"); return; }
|
||||
|
||||
const char* n = b->name;
|
||||
|
||||
if (strcmp(n, "开始") == 0) {
|
||||
// Follow output wire
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "移动物体") == 0) {
|
||||
Value dx = get_input_value(b->id, 1);
|
||||
Value dy = get_input_value(b->id, 2);
|
||||
Value dz = get_input_value(b->id, 3);
|
||||
printf(" [move] dx=%.1f dy=%.1f dz=%.1f\n", dx.num, dy.num, dz.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "旋转物体") == 0) {
|
||||
Value dx = get_input_value(b->id, 1);
|
||||
Value dy = get_input_value(b->id, 2);
|
||||
Value dz = get_input_value(b->id, 3);
|
||||
printf(" [rotate] rx=%.1f ry=%.1f rz=%.1f\n", dx.num, dy.num, dz.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "当按键") == 0) {
|
||||
// Event: just follow output (simulated - always fires)
|
||||
printf(" [key event] key='%s'\n", b->data);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "当点击") == 0) {
|
||||
printf(" [click event]\n");
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "打印") == 0 || strcmp(n, "print") == 0) {
|
||||
Value msg = get_input_value(b->id, 1);
|
||||
printf(" [print] %s\n", msg.str[0] ? msg.str : b->data);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "等待") == 0 || strcmp(n, "wait") == 0) {
|
||||
Value secs = get_input_value(b->id, 1);
|
||||
double s = secs.num > 0 ? secs.num : atof(b->data);
|
||||
printf(" [wait] %.1fs\n", s);
|
||||
// In real engine, this would pause. For now, just continue.
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "循环") == 0 || strcmp(n, "loop") == 0) {
|
||||
Value count = get_input_value(b->id, 1);
|
||||
int n = count.num > 0 ? (int)count.num : atoi(b->data);
|
||||
if (n <= 0) n = 1;
|
||||
printf(" [loop] %d times\n", n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Block* body = follow_wire(b->id, 0);
|
||||
execute(body, depth + 1);
|
||||
}
|
||||
}
|
||||
else if (strcmp(n, "如果") == 0 || strcmp(n, "if") == 0) {
|
||||
Value cond = get_input_value(b->id, 1);
|
||||
printf(" [if] condition=%d\n", cond.bool_val);
|
||||
Block* next = follow_wire(b->id, cond.bool_val ? 0 : 1);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "数学运算") == 0 || strcmp(n, "+") == 0) {
|
||||
Value a = get_input_value(b->id, 0);
|
||||
Value b2 = get_input_value(b->id, 1);
|
||||
b->outputs[0].num = a.num + b2.num;
|
||||
printf(" [add] %.1f + %.1f = %.1f\n", a.num, b2.num, b->outputs[0].num);
|
||||
}
|
||||
else if (strcmp(n, "变量设置") == 0 || strcmp(n, "set_var") == 0) {
|
||||
Value v = get_input_value(b->id, 1);
|
||||
set_var(b->data, (int)v.num);
|
||||
printf(" [set_var] %s = %d\n", b->data, (int)v.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "变量读取") == 0 || strcmp(n, "get_var") == 0) {
|
||||
int v = get_var(b->data);
|
||||
b->outputs[0].num = v;
|
||||
printf(" [get_var] %s = %d\n", b->data, v);
|
||||
}
|
||||
else {
|
||||
printf(" [unknown] '%s'\n", n);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void execute(Block* block, int depth) {
|
||||
if (!block) return;
|
||||
execute_block(block, depth);
|
||||
}
|
||||
|
||||
// === 主函数 ===
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const char* script = "Demo/test.ly";
|
||||
if (argc > 1) script = argv[1];
|
||||
|
||||
printf("=== lity3d .ly Interpreter ===\n");
|
||||
printf("Script: %s\n\n", script);
|
||||
|
||||
if (!parse_ly(script)) return 1;
|
||||
|
||||
printf("\n--- Blocks ---\n");
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
printf(" [%d] %s data='%s' pos=(%.0f,%.0f)\n", g_blocks[i].id, g_blocks[i].name, g_blocks[i].data, g_blocks[i].x, g_blocks[i].y);
|
||||
|
||||
printf("\n--- Wires ---\n");
|
||||
for (int i = 0; i < g_wire_count; i++)
|
||||
printf(" [%d].out%d -> [%d].in%d\n", g_wires[i].from_block, g_wires[i].from_slot, g_wires[i].to_block, g_wires[i].to_slot);
|
||||
|
||||
printf("\n--- Execute ---\n");
|
||||
|
||||
// Find start block
|
||||
Block* start = NULL;
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
if (strcmp(g_blocks[i].name, "开始") == 0) { start = &g_blocks[i]; break; }
|
||||
|
||||
if (!start) {
|
||||
// Try to find any block with incoming wires as entry point
|
||||
// Or just execute the first block
|
||||
if (g_block_count > 0) start = &g_blocks[0];
|
||||
}
|
||||
|
||||
if (start) {
|
||||
execute(start, 0);
|
||||
} else {
|
||||
printf("No executable blocks found.\n");
|
||||
}
|
||||
|
||||
printf("\n--- Done ---\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
#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/Scene/scene_serialize.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.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_mouse_x = 0, g_last_mouse_y = 0;
|
||||
static int g_mouse_first = 1;
|
||||
|
||||
static SceneNode* create_primitive_node(Scene* scene, SceneNode* parent, AssetManager* am,
|
||||
ID3D11Device* dev, const char* name, MeshType type,
|
||||
Vec3 pos, Vec3 rot, Vec3 scale,
|
||||
Material* material) {
|
||||
SceneNode* node = scene_create_node(scene, name);
|
||||
if (!node) return NULL;
|
||||
if (parent) scene_set_parent(node, parent);
|
||||
node->position = pos;
|
||||
node->scale = scale;
|
||||
quat_from_euler(rot.x, rot.y, rot.z, &node->rotation);
|
||||
|
||||
Asset* mesh_asset = asset_manager_load_mesh(am, dev, name);
|
||||
if (!mesh_asset) {
|
||||
const char* builtin = NULL;
|
||||
if (type == MESH_CUBE) builtin = "cube";
|
||||
else if (type == MESH_SPHERE) builtin = "sphere";
|
||||
else if (type == MESH_PLANE) builtin = "plane";
|
||||
if (builtin) mesh_asset = asset_manager_load_mesh(am, dev, builtin);
|
||||
}
|
||||
|
||||
if (mesh_asset && material) {
|
||||
MeshRenderer* mr = mesh_renderer_create(type, (Mesh*)asset_data(mesh_asset), material);
|
||||
scene_node_set_mesh_renderer(node, mr);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static Scene* create_default_scene(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* shader = (Shader*)asset_data(g_shader_asset);
|
||||
|
||||
Material* mat_red = material_create(shader, NULL);
|
||||
mat_red->color = (Vec4){1.0f, 0.3f, 0.2f, 1.0f};
|
||||
|
||||
Material* mat_blue = material_create(shader, NULL);
|
||||
mat_blue->color = (Vec4){0.2f, 0.5f, 1.0f, 1.0f};
|
||||
|
||||
Material* mat_ground = material_create(shader, NULL);
|
||||
mat_ground->color = (Vec4){0.3f, 0.3f, 0.35f, 1.0f};
|
||||
|
||||
// 中心红色立方体
|
||||
create_primitive_node(scene, root, am, dev, "cube", MESH_CUBE,
|
||||
(Vec3){0, 0, 0}, (Vec3){0, 0, 0}, (Vec3){1, 1, 1}, mat_red);
|
||||
// 右侧蓝色球体
|
||||
create_primitive_node(scene, root, am, dev, "sphere", MESH_SPHERE,
|
||||
(Vec3){2.0f, 0, 0}, (Vec3){0, 0, 0}, (Vec3){0.8f, 0.8f, 0.8f}, mat_blue);
|
||||
// 下方地面
|
||||
create_primitive_node(scene, root, am, dev, "ground", MESH_PLANE,
|
||||
(Vec3){0, -1.0f, 0}, (Vec3){0, 0, 0}, (Vec3){1, 1, 1}, mat_ground);
|
||||
|
||||
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);
|
||||
|
||||
if (engine->frame_count == 60) {
|
||||
graphics_device_save_screenshot(dev, "screenshot1.bmp");
|
||||
}
|
||||
if (engine->frame_count == 180) {
|
||||
graphics_device_save_screenshot(dev, "screenshot2.bmp");
|
||||
}
|
||||
}
|
||||
|
||||
static void on_update(Engine* engine, double dt) {
|
||||
(void)engine; (void)dt;
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
if (key == 'W' || key == 'w') camera_move_forward(&g_camera, 0.5f);
|
||||
if (key == 'S' || key == 's') camera_move_forward(&g_camera, -0.5f);
|
||||
if (key == 'A' || key == 'a') camera_move_right(&g_camera, -0.5f);
|
||||
if (key == 'D' || key == 'd') camera_move_right(&g_camera, 0.5f);
|
||||
if (key == VK_LEFT) camera_rotate_yaw(&g_camera, -0.1f);
|
||||
if (key == VK_RIGHT) camera_rotate_yaw(&g_camera, 0.1f);
|
||||
if (key == VK_UP) camera_rotate_pitch(&g_camera, -0.1f);
|
||||
if (key == VK_DOWN) camera_rotate_pitch(&g_camera, 0.1f);
|
||||
}
|
||||
|
||||
static void on_mouse_move(Engine* engine, int x, int y) {
|
||||
(void)engine;
|
||||
if (g_mouse_down[0]) {
|
||||
if (g_mouse_first) {
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
g_mouse_first = 0;
|
||||
} else {
|
||||
float dx = (float)(x - g_last_mouse_x);
|
||||
float dy = (float)(y - g_last_mouse_y);
|
||||
camera_rotate_yaw(&g_camera, dx * 0.005f);
|
||||
camera_rotate_pitch(&g_camera, dy * 0.005f);
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
}
|
||||
} 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 = "Lity3D - Scene Demo";
|
||||
config.vsync = 0;
|
||||
config.window_width = 1280;
|
||||
config.window_height = 720;
|
||||
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &config)) {
|
||||
LOG_FATAL("Engine 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 load failed");
|
||||
return -1;
|
||||
}
|
||||
LOG_INFO("Shader loaded via AssetManager");
|
||||
|
||||
Shader* default_shader = (Shader*)asset_data(g_shader_asset);
|
||||
|
||||
g_scene = scene_load("scene.txt", dev->device, default_shader);
|
||||
if (!g_scene) {
|
||||
LOG_INFO("No scene.txt found, creating default scene");
|
||||
g_scene = create_default_scene(g_assets, dev->device);
|
||||
if (!scene_save(g_scene, "scene.txt")) {
|
||||
LOG_WARN("Failed to save scene.txt");
|
||||
}
|
||||
}
|
||||
|
||||
float aspect = (float)config.window_width / config.window_height;
|
||||
g_camera = camera_perspective(1.0472f, aspect, 0.1f, 100.0f);
|
||||
g_camera.position = (Vec3){0, 0.5f, -5.0f};
|
||||
g_camera.target = (Vec3){0, 0, 0};
|
||||
g_camera.dirty = 1;
|
||||
|
||||
renderer_set_view(r, camera_get_view(&g_camera));
|
||||
renderer_set_projection(r, camera_get_projection(&g_camera));
|
||||
|
||||
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("Running scene demo...");
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// mesh_debug.c - 精确定位 mesh 系统 bug
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static ID3D11Buffer* g_vb = NULL;
|
||||
static ID3D11Buffer* g_ib = NULL;
|
||||
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
float sw=(float)g_dev->width, sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f), asp=sw/sh;
|
||||
|
||||
float mvp[16];
|
||||
mvp[0]=fov/asp; mvp[5]=-fov; mvp[10]=1; mvp[11]=-1; mvp[14]=0.1f; mvp[15]=1;
|
||||
Mat4 pm, pt; memcpy(&pm, mvp, sizeof(Mat4)); mat4_transpose(&pm, &pt);
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
D3D11_VIEWPORT vp={}; vp.Width=sw; vp.Height=sh; vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={}; rd.FillMode=D3D11_FILL_SOLID; rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs=NULL; g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={}; dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState* dss=NULL; g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&pt);
|
||||
|
||||
// 用 init 时创建的 VB 画
|
||||
UINT stride=sizeof(V), offset=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&g_vb,&stride,&offset);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,g_ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
|
||||
if(rs) rs->lpVtbl->Release(rs);
|
||||
if(dss) dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if(key==VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) {
|
||||
EngineConfig cfg=engine_default_config(); cfg.app_name="mesh debug";
|
||||
Engine* e=engine_create(); if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
g_shader=shader_create(); shader_compile(g_shader,g_dev->device,NULL,NULL,0,0);
|
||||
|
||||
// WinMain 中创建 VB/IB(跟 mesh_create_cube 一样的时机)
|
||||
V v[4]={{{-0.5f,-0.5f,0.5f},{0,0,1},{0,0},{1,0,0,1}},{{0.5f,-0.5f,0.5f},{0,0,1},{1,0},{0,1,0,1}},{{0.5f,0.5f,0.5f},{0,0,1},{1,1},{0,0,1,1}},{{-0.5f,0.5f,0.5f},{0,0,1},{0,1},{1,1,1,1}}};
|
||||
uint32_t idx[6]={0,1,2,0,2,3};
|
||||
D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&g_vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&g_ib);
|
||||
|
||||
engine_set_render_callback(e,on_render); engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
if(g_vb)g_vb->lpVtbl->Release(g_vb); if(g_ib)g_ib->lpVtbl->Release(g_ib);
|
||||
shader_destroy(g_shader); graphics_device_destroy(g_dev); engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static ID3D11Device* g_dev; static ID3D11DeviceContext* g_ctx;
|
||||
static IDXGISwapChain* g_sc; static ID3D11RenderTargetView* g_rtv;
|
||||
static ID3D11VertexShader* g_vs; static ID3D11PixelShader* g_ps;
|
||||
static ID3D11InputLayout* g_il; static ID3D11Buffer* g_cb;
|
||||
|
||||
static float cam_dist = 5.0f, cam_yaw = 0.5f, cam_pitch = 0.3f;
|
||||
static int drag = 0, last_mx, last_my;
|
||||
static int key_w=0,key_s=0,key_a=0,key_d=0,key_q=0,key_e=0;
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
|
||||
static V3D* obj_verts = NULL;
|
||||
static uint32_t* obj_idx = NULL;
|
||||
static int obj_vcount = 0, obj_icount = 0;
|
||||
static ID3D11Buffer* obj_vb = NULL;
|
||||
static ID3D11Buffer* obj_ib = NULL;
|
||||
|
||||
static int LoadOBJ(const char* path) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return -1;
|
||||
int max_v = 16384, max_f = 32768;
|
||||
float* vpos = (float*)malloc(max_v * 3 * sizeof(float));
|
||||
int vc = 0;
|
||||
int* fidx = (int*)malloc(max_f * 3 * sizeof(int));
|
||||
int fc = 0;
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (line[0] == 'v' && line[1] == ' ') {
|
||||
float x, y, z;
|
||||
if (sscanf(line + 2, "%f %f %f", &x, &y, &z) == 3 && vc < max_v) {
|
||||
vpos[vc*3]=x; vpos[vc*3+1]=y; vpos[vc*3+2]=z; vc++;
|
||||
}
|
||||
} else if (line[0] == 'f' && line[1] == ' ') {
|
||||
int v0, v1, v2;
|
||||
char* p = line + 2;
|
||||
v0 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v1 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v2 = atoi(p) - 1;
|
||||
if (v0 >= 0 && v1 >= 0 && v2 >= 0 && fc < max_f) {
|
||||
fidx[fc*3]=v0; fidx[fc*3+1]=v1; fidx[fc*3+2]=v2; fc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (vc == 0 || fc == 0) { free(vpos); free(fidx); return -1; }
|
||||
|
||||
obj_vcount = fc * 3;
|
||||
obj_icount = fc * 3;
|
||||
obj_verts = (V3D*)calloc(obj_vcount, sizeof(V3D));
|
||||
obj_idx = (uint32_t*)malloc(obj_icount * sizeof(uint32_t));
|
||||
|
||||
for (int i = 0; i < fc; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int vi = fidx[i*3+j];
|
||||
int oi = i*3+j;
|
||||
if (vi < vc) {
|
||||
obj_verts[oi].p[0] = vpos[vi*3];
|
||||
obj_verts[oi].p[1] = vpos[vi*3+1];
|
||||
obj_verts[oi].p[2] = vpos[vi*3+2];
|
||||
}
|
||||
obj_verts[oi].c[0] = 0.6f; obj_verts[oi].c[1] = 0.7f; obj_verts[oi].c[2] = 0.8f; obj_verts[oi].c[3] = 1;
|
||||
obj_idx[oi] = oi;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < fc; i++) {
|
||||
float* p0 = obj_verts[i*3].p;
|
||||
float* p1 = obj_verts[i*3+1].p;
|
||||
float* p2 = obj_verts[i*3+2].p;
|
||||
float e1[3]={p1[0]-p0[0],p1[1]-p0[1],p1[2]-p0[2]};
|
||||
float e2[3]={p2[0]-p0[0],p2[1]-p0[1],p2[2]-p0[2]};
|
||||
float nx=e1[1]*e2[2]-e1[2]*e2[1], ny=e1[2]*e2[0]-e1[0]*e2[2], nz=e1[0]*e2[1]-e1[1]*e2[0];
|
||||
float nl=sqrtf(nx*nx+ny*ny+nz*nz);
|
||||
if(nl>0.0001f){nx/=nl;ny/=nl;nz/=nl;}
|
||||
for(int j=0;j<3;j++){obj_verts[i*3+j].n[0]=nx;obj_verts[i*3+j].n[1]=ny;obj_verts[i*3+j].n[2]=nz;}
|
||||
}
|
||||
|
||||
D3D11_BUFFER_DESC bd; D3D11_SUBRESOURCE_DATA sd;
|
||||
memset(&bd,0,sizeof(bd));memset(&sd,0,sizeof(sd));
|
||||
bd.ByteWidth=sizeof(V3D)*obj_vcount;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=obj_verts;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&obj_vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*obj_icount;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=obj_idx;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&obj_ib);
|
||||
|
||||
free(vpos); free(fidx); free(obj_verts); free(obj_idx);
|
||||
obj_verts = NULL; obj_idx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Init(HWND h) {
|
||||
HRESULT hr;
|
||||
DXGI_SWAP_CHAIN_DESC sd;memset(&sd,0,sizeof(sd));sd.BufferCount=2;sd.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;sd.BufferDesc.RefreshRate.Numerator=60;sd.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;sd.OutputWindow=h;sd.SampleDesc.Count=1;sd.Windowed=TRUE;sd.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_11_0,gt;hr=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,&fl,1,D3D11_SDK_VERSION,&sd,&g_sc,&g_dev,>,&g_ctx);if(FAILED(hr))return;
|
||||
ID3D11Texture2D*bb=NULL;hr=g_sc->lpVtbl->GetBuffer(g_sc,0,&IID_ID3D11Texture2D,(void**)&bb);if(FAILED(hr)||!bb)return;hr=g_dev->lpVtbl->CreateRenderTargetView(g_dev,(ID3D11Resource*)bb,NULL,&g_rtv);bb->lpVtbl->Release(bb);if(FAILED(hr))return;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
const char*ps="struct I{float3 n:NORMAL;float4 c:COLOR;};float4 main(float4 p:SV_POSITION,I i):SV_Target{float l=normalize(float3(0.3,1,0.5));float d=max(dot(normalize(i.n),l),0.2);return float4(i.c.rgb*d,1);}";
|
||||
ID3DBlob*b1,*b2,*e;D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);if(e){e->lpVtbl->Release(e);e=NULL;}D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);if(e){e->lpVtbl->Release(e);e=NULL;}if(!b1||!b2)return;
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);g_dev->lpVtbl->CreatePixelShader(g_dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];memset(el,0,sizeof(el));el[0].SemanticName="POSITION";el[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[1].SemanticName="NORMAL";el[1].AlignedByteOffset=12;el[1].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[2].SemanticName="TEXCOORD";el[2].AlignedByteOffset=24;el[2].Format=DXGI_FORMAT_R32G32_FLOAT;el[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[3].SemanticName="COLOR";el[3].AlignedByteOffset=32;el[3].Format=DXGI_FORMAT_R32G32B32A32_FLOAT;el[3].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev,el,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;memset(&cbd,0,sizeof(cbd));cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;g_dev->lpVtbl->CreateBuffer(g_dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void mat4_perspective(float* m, float fov, float asp, float zn, float zf) {
|
||||
memset(m, 0, 64);
|
||||
float f = 1.0f / tanf(fov / 2);
|
||||
m[0] = f / asp; m[5] = -f;
|
||||
m[10] = zf / (zf - zn); m[11] = -zn * zf / (zf - zn);
|
||||
m[14] = 1; m[15] = 0;
|
||||
}
|
||||
|
||||
static void mat4_lookat(float* m, float ex, float ey, float ez, float tx, float ty, float tz) {
|
||||
float fx=tx-ex, fy=ty-ey, fz=tz-ez;
|
||||
float fl=sqrtf(fx*fx+fy*fy+fz*fz);fx/=fl;fy/=fl;fz/=fl;
|
||||
float rx=fy*0-fz*1,ry=fz*0-fx*0,rz=fx*1-fy*0;
|
||||
float rl=sqrtf(rx*rx+ry*ry+rz*rz);rx/=rl;ry/=rl;rz/=rl;
|
||||
float ux=ry*fz-rz*fy,uy=rz*fx-rx*fz,uz=rx*fy-ry*fx;
|
||||
memset(m, 0, 64);
|
||||
m[0]=rx*1;m[1]=ux*1;m[2]=fx*1;
|
||||
m[4]=ry*1;m[5]=uy*1;m[6]=fy*1;
|
||||
m[8]=rz*1;m[9]=uz*1;m[10]=fz*1;
|
||||
m[12]=-(rx*ex+ry*ey+rz*ez);m[13]=-(ux*ex+uy*ey+uz*ez);m[14]=-(fx*ex+fy*ey+fz*ez);m[15]=1;
|
||||
}
|
||||
|
||||
static void mat4_mul(float* o, float* a, float* b) {
|
||||
float t[16];for(int i=0;i<4;i++)for(int j=0;j<4;j++){t[i*4+j]=0;for(int k=0;k<4;k++)t[i*4+j]+=a[i*4+k]*b[k*4+j];}
|
||||
memcpy(o,t,64);
|
||||
}
|
||||
|
||||
static void Frame(void) {
|
||||
float dt = 0.016f, rspd = 2.0f * dt, mspeed = 3.0f * dt;
|
||||
if (key_a) cam_yaw -= rspd; if (key_d) cam_yaw += rspd;
|
||||
if (key_q) cam_pitch -= rspd; if (key_e) cam_pitch += rspd;
|
||||
if (key_w) cam_dist -= mspeed; if (key_s) cam_dist += mspeed;
|
||||
if (cam_dist < 1.0f) cam_dist = 1.0f; if (cam_dist > 20.0f) cam_dist = 20.0f;
|
||||
if (cam_pitch > 1.5f) cam_pitch = 1.5f; if (cam_pitch < -1.5f) cam_pitch = -1.5f;
|
||||
|
||||
float ex = cam_dist * sinf(cam_yaw) * cosf(cam_pitch);
|
||||
float ey = cam_dist * sinf(cam_pitch);
|
||||
float ez = cam_dist * cosf(cam_yaw) * cosf(cam_pitch);
|
||||
|
||||
float view[16], proj[16], vp[16], tmp[16];
|
||||
mat4_lookat(view, ex, ey, ez, 0, 0, 0);
|
||||
mat4_perspective(proj, 0.8f, 1280.0f/720.0f, 0.1f, 100.0f);
|
||||
mat4_mul(tmp, view, proj);
|
||||
float vp_t[16]; for(int i=0;i<4;i++)for(int j=0;j<4;j++) vp_t[i*4+j]=tmp[j*4+i];
|
||||
|
||||
float cl[4]={.15f,.18f,.22f,1};
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx,1,&g_rtv,NULL);g_ctx->lpVtbl->ClearRenderTargetView(g_ctx,g_rtv,cl);
|
||||
D3D11_VIEWPORT vp2;memset(&vp2,0,sizeof(vp2));vp2.Width=1280;vp2.Height=720;vp2.MaxDepth=1;g_ctx->lpVtbl->RSSetViewports(g_ctx,1,&vp2);
|
||||
D3D11_RASTERIZER_DESC rd;memset(&rd,0,sizeof(rd));rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;ID3D11RasterizerState*rs;g_dev->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);g_ctx->lpVtbl->RSSetState(g_ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds;memset(&ds,0,sizeof(ds));ds.DepthEnable=FALSE;ID3D11DepthStencilState*dss;g_dev->lpVtbl->CreateDepthStencilState(g_dev,&ds,&dss);g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx,dss,0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);g_ctx->lpVtbl->VSSetShader(g_ctx,g_vs,NULL,0);g_ctx->lpVtbl->PSSetShader(g_ctx,g_ps,NULL,0);g_ctx->lpVtbl->IASetInputLayout(g_ctx,g_il);g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx,0,1,&g_cb);g_ctx->lpVtbl->UpdateSubresource(g_ctx,(ID3D11Resource*)g_cb,0,NULL,vp_t,0,0);
|
||||
|
||||
if (obj_vb && obj_ib) {
|
||||
UINT stride = sizeof(V3D), off = 0;
|
||||
g_ctx->lpVtbl->IASetVertexBuffers(g_ctx, 0, 1, &obj_vb, &stride, &off);
|
||||
g_ctx->lpVtbl->IASetIndexBuffer(g_ctx, obj_ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
g_ctx->lpVtbl->DrawIndexed(g_ctx, obj_icount, 0, 0);
|
||||
}
|
||||
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
g_sc->lpVtbl->Present(g_sc, 1, 0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h,UINT m,WPARAM w,LPARAM l){
|
||||
switch(m){
|
||||
case WM_LBUTTONDOWN:drag=1;last_mx=(short)LOWORD(l);last_my=(short)HIWORD(l);SetCapture(h);break;
|
||||
case WM_LBUTTONUP:drag=0;ReleaseCapture();break;
|
||||
case WM_MOUSEMOVE:if(drag){int mx=(short)LOWORD(l),my=(short)HIWORD(l);cam_yaw+=(mx-last_mx)*0.005f;cam_pitch+=(my-last_my)*0.005f;if(cam_pitch>1.5f)cam_pitch=1.5f;if(cam_pitch<-1.5f)cam_pitch=-1.5f;last_mx=mx;last_my=my;}break;
|
||||
case WM_MOUSEWHEEL:cam_dist-=(short)HIWORD(w)/120.0f;if(cam_dist<1)cam_dist=1;if(cam_dist>20)cam_dist=20;break;
|
||||
case WM_KEYDOWN:switch(w){case 'A':key_a=1;break;case 'D':key_d=1;break;case 'W':key_w=1;break;case 'S':key_s=1;break;case 'Q':key_q=1;break;case 'E':key_e=1;break;case VK_ESCAPE:PostQuitMessage(0);break;}break;
|
||||
case WM_KEYUP:switch(w){case 'A':key_a=0;break;case 'D':key_d=0;break;case 'W':key_w=0;break;case 'S':key_s=0;break;case 'Q':key_q=0;break;case 'E':key_e=0;break;}break;
|
||||
case WM_DESTROY:PostQuitMessage(0);return 0;
|
||||
}return DefWindowProcW(h,m,w,l);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR nC,int nS){
|
||||
(void)nS;
|
||||
WNDCLASSEXW wc;memset(&wc,0,sizeof(wc));wc.cbSize=sizeof(wc);wc.style=CS_CLASSDC;wc.lpfnWndProc=WP;wc.hInstance=hI;wc.lpszClassName=L"obj_viewer";
|
||||
RegisterClassExW(&wc);
|
||||
HWND hwnd=CreateWindowW(L"obj_viewer",L"OBJ Viewer - Mouse drag orbit, WASD move, Scroll zoom",WS_OVERLAPPEDWINDOW,100,100,1280,720,NULL,NULL,hI,NULL);
|
||||
if(!hwnd)return -1;ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);Init(hwnd);
|
||||
|
||||
char path[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, path, MAX_PATH);
|
||||
char* sl = strrchr(path, '\\');
|
||||
if (sl) { *(sl+1) = '\0'; strcat(path, "Assets\\cube.obj"); }
|
||||
else strcpy(path, "Assets\\cube.obj");
|
||||
LoadOBJ(path);
|
||||
|
||||
MSG msg;
|
||||
while(1){while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);if(msg.message==WM_QUIT)goto done;}Frame();}
|
||||
done:
|
||||
if(obj_vb)obj_vb->lpVtbl->Release(obj_vb);if(obj_ib)obj_ib->lpVtbl->Release(obj_ib);
|
||||
if(g_cb)g_cb->lpVtbl->Release(g_cb);if(g_il)g_il->lpVtbl->Release(g_il);if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_rtv)g_rtv->lpVtbl->Release(g_rtv);if(g_sc)g_sc->lpVtbl->Release(g_sc);if(g_ctx)g_ctx->lpVtbl->Release(g_ctx);if(g_dev)g_dev->lpVtbl->Release(g_dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
#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/camera.h"
|
||||
#include "../Engine/Rendering/camera_controller.h"
|
||||
#include "../Engine/Terrain/terrain.h"
|
||||
#include "../Engine/Terrain/terrain_manager.h"
|
||||
#include "../Engine/Rendering/frustum.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/Scene/scene_render.h"
|
||||
#include "../Engine/Scene/scene_serialize.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <Windows.h>
|
||||
|
||||
static AssetManager* g_assets = NULL;
|
||||
static Asset* g_shader_asset = NULL;
|
||||
static Camera g_camera;
|
||||
static CameraController g_controller;
|
||||
static TerrainManager* g_terrain = NULL;
|
||||
static Material* g_terrain_mat = NULL;
|
||||
static Mesh* g_cube = NULL;
|
||||
static Material* g_cube_mat = NULL;
|
||||
static Mesh* g_water = NULL;
|
||||
static Material* g_water_mat = NULL;
|
||||
static Scene* g_test_scene = NULL;
|
||||
|
||||
static int g_mouse_down[3] = {0};
|
||||
static int g_last_mouse_x = 0, g_last_mouse_y = 0;
|
||||
static int g_mouse_first = 1;
|
||||
static int g_walk_mode = 0;
|
||||
|
||||
// ============================================================================
|
||||
// 简易植被/岩石散布
|
||||
// ============================================================================
|
||||
#define MAX_SCATTER 512
|
||||
|
||||
typedef struct {
|
||||
Mesh* mesh;
|
||||
Material* mat;
|
||||
Mat4 world;
|
||||
} ScatterInstance;
|
||||
|
||||
static ScatterInstance g_scatter[MAX_SCATTER];
|
||||
static int g_scatter_count = 0;
|
||||
|
||||
static void add_scatter(Mesh* mesh, Material* mat, Vec3 pos, Vec3 scale) {
|
||||
if (g_scatter_count >= MAX_SCATTER) return;
|
||||
ScatterInstance* s = &g_scatter[g_scatter_count++];
|
||||
s->mesh = mesh;
|
||||
s->mat = mat;
|
||||
mat4_identity(&s->world);
|
||||
s->world.m[0][0] = scale.x;
|
||||
s->world.m[1][1] = scale.y;
|
||||
s->world.m[2][2] = scale.z;
|
||||
s->world.m[3][0] = pos.x;
|
||||
s->world.m[3][1] = pos.y;
|
||||
s->world.m[3][2] = pos.z;
|
||||
}
|
||||
|
||||
static void generate_scatter(ID3D11Device* dev, Shader* shader) {
|
||||
Mesh* rock_mesh = mesh_create_cube(dev);
|
||||
Material* rock_mat = material_create(shader, NULL);
|
||||
rock_mat->color = (Vec4){0.55f, 0.50f, 0.45f, 1.0f};
|
||||
|
||||
Mesh* trunk_mesh = mesh_create_cube(dev);
|
||||
Material* trunk_mat = material_create(shader, NULL);
|
||||
trunk_mat->color = (Vec4){0.55f, 0.40f, 0.25f, 1.0f};
|
||||
|
||||
Mesh* leaves_mesh = mesh_create_sphere(dev, 1.0f, 8);
|
||||
Material* leaves_mat = material_create(shader, NULL);
|
||||
leaves_mat->color = (Vec4){0.22f, 0.65f, 0.28f, 1.0f};
|
||||
|
||||
for (int i = 0; i < MAX_SCATTER; i++) {
|
||||
float x = ((float)rand() / (float)RAND_MAX) * 400.0f - 200.0f;
|
||||
float z = ((float)rand() / (float)RAND_MAX) * 400.0f - 200.0f;
|
||||
float h = terrain_manager_get_height(g_terrain, x, z);
|
||||
// 跳过过低(水)或过高的山顶
|
||||
if (h < -2.0f || h > 20.0f) continue;
|
||||
|
||||
int type = rand() % 3;
|
||||
if (type == 0) {
|
||||
// 岩石
|
||||
float s = 1.0f + ((float)rand() / (float)RAND_MAX) * 2.0f;
|
||||
Vec3 pos = {x, h + s * 0.3f, z};
|
||||
Vec3 sc = {s, s * 0.6f, s};
|
||||
add_scatter(rock_mesh, rock_mat, pos, sc);
|
||||
} else {
|
||||
// 树
|
||||
float trunk_h = 1.5f + ((float)rand() / (float)RAND_MAX) * 1.5f;
|
||||
Vec3 trunk_pos = {x, h + trunk_h * 0.5f, z};
|
||||
Vec3 trunk_sc = {0.25f, trunk_h, 0.25f};
|
||||
add_scatter(trunk_mesh, trunk_mat, trunk_pos, trunk_sc);
|
||||
|
||||
float leaves_s = 1.2f + ((float)rand() / (float)RAND_MAX) * 1.2f;
|
||||
Vec3 leaves_pos = {x, h + trunk_h + leaves_s * 0.4f, z};
|
||||
Vec3 leaves_sc = {leaves_s, leaves_s, leaves_s};
|
||||
add_scatter(leaves_mesh, leaves_mat, leaves_pos, leaves_sc);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Generated %d scatter instances", g_scatter_count);
|
||||
}
|
||||
|
||||
static void render_scatter(Renderer* r, const Vec4 planes[6]) {
|
||||
const float cull_distance = 140.0f;
|
||||
const float cull_dist2 = cull_distance * cull_distance;
|
||||
int rendered = 0;
|
||||
for (int i = 0; i < g_scatter_count; i++) {
|
||||
ScatterInstance* s = &g_scatter[i];
|
||||
Vec3 pos = {s->world.m[3][0], s->world.m[3][1], s->world.m[3][2]};
|
||||
Vec3 d;
|
||||
vec3_sub(&pos, &g_camera.position, &d);
|
||||
if (vec3_dot(&d, &d) > cull_dist2) continue;
|
||||
|
||||
// 视锥剔除:用包围球近似
|
||||
float radius = fmaxf(fmaxf(s->world.m[0][0], s->world.m[1][1]), s->world.m[2][2]) * 0.866f;
|
||||
if (!frustum_intersects_sphere(planes, pos, radius)) continue;
|
||||
|
||||
renderer_draw_mesh_with_material(r, s->mesh, s->mat, &s->world);
|
||||
rendered++;
|
||||
}
|
||||
LOG_INFO("Scatter render: visible=%d/%d", rendered, g_scatter_count);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 地形高度回调
|
||||
// ============================================================================
|
||||
static float get_terrain_height(float x, float z, void* user) {
|
||||
(void)user;
|
||||
if (g_terrain) return terrain_manager_get_height(g_terrain, x, z);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 引擎回调
|
||||
// ============================================================================
|
||||
static void on_render(Engine* engine) {
|
||||
Renderer* r = engine_get_renderer(engine);
|
||||
GraphicsDevice* dev = engine_get_graphics_device(engine);
|
||||
if (!r || !dev) return;
|
||||
|
||||
renderer_set_view(r, camera_get_view(&g_camera));
|
||||
renderer_set_projection(r, camera_get_projection(&g_camera));
|
||||
|
||||
renderer_begin_frame(r);
|
||||
|
||||
Mat4 vp;
|
||||
renderer_get_view_projection(r, &vp);
|
||||
Vec4 planes[6];
|
||||
frustum_from_matrix(&vp, planes);
|
||||
|
||||
if (g_water) {
|
||||
Mat4 water_world;
|
||||
mat4_identity(&water_world);
|
||||
water_world.m[3][1] = -5.0f;
|
||||
renderer_draw_mesh_with_material(r, g_water, g_water_mat, &water_world);
|
||||
}
|
||||
|
||||
if (g_terrain) {
|
||||
terrain_manager_update(g_terrain, g_camera.position);
|
||||
terrain_manager_render(g_terrain, r);
|
||||
}
|
||||
|
||||
render_scatter(r, planes);
|
||||
|
||||
if (g_test_scene) {
|
||||
scene_update(g_test_scene);
|
||||
scene_render(g_test_scene, r);
|
||||
}
|
||||
|
||||
renderer_end_frame(r);
|
||||
|
||||
if (engine->frame_count == 60) {
|
||||
graphics_device_save_screenshot(dev, "open_world_screenshot1.bmp");
|
||||
}
|
||||
if (engine->frame_count == 180) {
|
||||
graphics_device_save_screenshot(dev, "open_world_screenshot2.bmp");
|
||||
}
|
||||
}
|
||||
|
||||
static void on_update(Engine* engine, double dt) {
|
||||
(void)engine;
|
||||
float fdt = (float)dt;
|
||||
|
||||
Vec3 dir = {0.0f, 0.0f, 0.0f};
|
||||
if (GetAsyncKeyState('W') & 0x8000) dir.z += 1.0f;
|
||||
if (GetAsyncKeyState('S') & 0x8000) dir.z -= 1.0f;
|
||||
if (GetAsyncKeyState('A') & 0x8000) dir.x -= 1.0f;
|
||||
if (GetAsyncKeyState('D') & 0x8000) dir.x += 1.0f;
|
||||
|
||||
if (!g_walk_mode) {
|
||||
if (GetAsyncKeyState(VK_SPACE) & 0x8000) dir.y += 1.0f;
|
||||
if (GetAsyncKeyState(VK_SHIFT) & 0x8000) dir.y -= 1.0f;
|
||||
}
|
||||
|
||||
if (dir.x != 0.0f || dir.y != 0.0f || dir.z != 0.0f) {
|
||||
camera_controller_move(&g_controller, dir, fdt);
|
||||
}
|
||||
|
||||
camera_controller_update(&g_controller, fdt);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
(void)engine;
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
|
||||
// 切换步行/飞行模式
|
||||
if (key == 'F' || key == 'f') {
|
||||
g_walk_mode = !g_walk_mode;
|
||||
camera_controller_set_mode(&g_controller, g_walk_mode ? CAMERA_MODE_WALK : CAMERA_MODE_FLY);
|
||||
g_controller.move_speed = g_walk_mode ? 8.0f : 40.0f;
|
||||
LOG_INFO("Camera mode: %s (speed %.1f)", g_walk_mode ? "walk" : "fly", g_controller.move_speed);
|
||||
}
|
||||
|
||||
// 模式切换后重新定位相机高度
|
||||
if (g_walk_mode) {
|
||||
float ground = get_terrain_height(g_camera.position.x, g_camera.position.z, NULL);
|
||||
g_camera.position.y = ground + g_controller.height_offset;
|
||||
g_camera.target.y = g_camera.position.y + sinf(g_controller.pitch);
|
||||
g_camera.dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_mouse_move(Engine* engine, int x, int y) {
|
||||
(void)engine;
|
||||
if (g_mouse_down[0]) { // 左键拖拽旋转
|
||||
if (g_mouse_first) {
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
g_mouse_first = 0;
|
||||
} else {
|
||||
float dx = (float)(x - g_last_mouse_x);
|
||||
float dy = (float)(y - g_last_mouse_y);
|
||||
camera_controller_look(&g_controller, dx, dy);
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
}
|
||||
} 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;
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
EngineConfig config = engine_default_config();
|
||||
config.app_name = "Lity3D - Open World Demo";
|
||||
config.vsync = 1;
|
||||
config.window_width = 1280;
|
||||
config.window_height = 720;
|
||||
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &config)) {
|
||||
LOG_FATAL("Engine 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 load failed");
|
||||
return -1;
|
||||
}
|
||||
LOG_INFO("Shader loaded via AssetManager");
|
||||
|
||||
Shader* default_shader = (Shader*)asset_data(g_shader_asset);
|
||||
|
||||
// 地形材质
|
||||
g_terrain_mat = material_create(default_shader, NULL);
|
||||
g_terrain_mat->color = (Vec4){1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
// 参照立方体
|
||||
g_cube = mesh_create_cube(dev->device);
|
||||
g_cube_mat = material_create(default_shader, NULL);
|
||||
g_cube_mat->color = (Vec4){1.0f, 0.2f, 0.2f, 1.0f};
|
||||
|
||||
// 水面(不透明,作为低洼处背景)
|
||||
g_water = mesh_create_plane(dev->device, 2000.0f);
|
||||
g_water_mat = material_create(default_shader, NULL);
|
||||
g_water_mat->color = (Vec4){0.18f, 0.45f, 0.78f, 1.0f};
|
||||
|
||||
// 测试场景:仅保留一个红色立方体作为原点标记
|
||||
g_test_scene = (Scene*)calloc(1, sizeof(Scene));
|
||||
scene_init(g_test_scene);
|
||||
|
||||
SceneNode* cube_node = scene_create_node(g_test_scene, "cube");
|
||||
scene_set_parent(cube_node, g_test_scene->root);
|
||||
cube_node->position = (Vec3){0.0f, 0.0f, 0.0f};
|
||||
MeshRenderer* cube_mr = mesh_renderer_create(MESH_CUBE, g_cube, g_cube_mat);
|
||||
scene_node_set_mesh_renderer(cube_node, cube_mr);
|
||||
|
||||
// 地形配置
|
||||
TerrainConfig tcfg = terrain_default_config();
|
||||
tcfg.vertices_per_chunk = 48;
|
||||
tcfg.chunk_size = 64.0f;
|
||||
tcfg.height_scale = 30.0f;
|
||||
tcfg.uv_scale = 0.05f;
|
||||
|
||||
g_terrain = terrain_manager_create(dev->device, &tcfg, g_terrain_mat);
|
||||
g_terrain->load_radius = 3;
|
||||
|
||||
// 生成植被/岩石
|
||||
generate_scatter(dev->device, default_shader);
|
||||
|
||||
// 天空色与柔和环境光
|
||||
renderer_set_clear_color(r, 0.53f, 0.81f, 0.98f, 1.0f);
|
||||
renderer_set_light(r, (Vec3){0.5f, -1.0f, 0.3f},
|
||||
(Vec4){0.55f, 0.53f, 0.48f, 1.0f},
|
||||
(Vec4){0.70f, 0.74f, 0.82f, 1.0f});
|
||||
|
||||
// 相机初始化:站在地形上,朝 +Z
|
||||
float aspect = (float)config.window_width / (float)config.window_height;
|
||||
g_camera = camera_perspective(1.0472f, aspect, 0.1f, 500.0f);
|
||||
float start_h = terrain_manager_get_height(g_terrain, 0.0f, 0.0f);
|
||||
g_camera.position = (Vec3){0.0f, start_h + 1.75f, 0.0f};
|
||||
g_camera.target = (Vec3){0.0f, start_h + 1.75f, 5.0f};
|
||||
g_camera.far_z = 500.0f;
|
||||
g_camera.dirty = 1;
|
||||
|
||||
g_controller = camera_controller_create(&g_camera);
|
||||
g_controller.move_speed = 8.0f;
|
||||
g_controller.mouse_sensitivity = 0.004f;
|
||||
camera_controller_set_ground_callback(&g_controller, get_terrain_height, NULL);
|
||||
g_walk_mode = 1;
|
||||
camera_controller_set_mode(&g_controller, CAMERA_MODE_WALK);
|
||||
LOG_INFO("Starting in walk mode at height %.2f", start_h);
|
||||
|
||||
renderer_set_view(r, camera_get_view(&g_camera));
|
||||
renderer_set_projection(r, camera_get_projection(&g_camera));
|
||||
|
||||
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("Running open world demo...");
|
||||
engine_run(engine);
|
||||
|
||||
terrain_manager_destroy(g_terrain);
|
||||
if (g_test_scene) {
|
||||
scene_destroy_renderers(g_test_scene);
|
||||
scene_destroy(g_test_scene);
|
||||
free(g_test_scene);
|
||||
}
|
||||
if (g_cube) mesh_destroy(g_cube);
|
||||
asset_manager_destroy(g_assets);
|
||||
engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// raw3d_test.c - 用 draw_quad 画 3D 方块,验证场景图变换
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static Scene g_scene;
|
||||
static float g_time = 0;
|
||||
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
static void draw_quad_3d(ID3D11DeviceContext* ctx, float x, float y, float w, float h, float r, float g, float b, float a) {
|
||||
V v[4] = {{{x,y,0},{0,0,-1},{0,0},{r,g,b,a}},{{x+w,y,0},{0,0,-1},{1,0},{r,g,b,a}},{{x+w,y+h,0},{0,0,-1},{1,1},{r,g,b,a}},{{x,y+h,0},{0,0,-1},{0,1},{r,g,b,a}}};
|
||||
uint32_t idx[6] = {0,1,2,0,2,3};
|
||||
ID3D11Buffer *vb=NULL,*ib=NULL;
|
||||
D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&ib);
|
||||
UINT stride=sizeof(V),off=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&stride,&off);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
scene_update(&g_scene);
|
||||
g_time += (float)engine->delta_time;
|
||||
|
||||
float sw=(float)g_dev->width, sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f), asp=sw/sh;
|
||||
|
||||
// VP矩阵: 摄像机在(8,5,10)看原点
|
||||
float ex=8,ey=5,ez=10;
|
||||
float fx=-ex,fy=-ey,fz=-ez, fl=sqrtf(fx*fx+fy*fy+fz*fz); fx/=fl;fy/=fl;fz/=fl;
|
||||
float rx=fy*0-fz*1,ry=fz*0-fx*0,rz=fx*1-fy*0;
|
||||
float rl=sqrtf(rx*rx+ry*ry+rz*rz);rx/=rl;ry/=rl;rz/=rl;
|
||||
float ux=ry*fz-rz*fy,uy=rz*fx-rx*fz,uz=rx*fy-ry*fx;
|
||||
float mvp[16];
|
||||
mvp[0]=rx*fov/asp;mvp[1]=ry*fov/asp;mvp[2]=rz*fov/asp;mvp[3]=0;
|
||||
mvp[4]=ux*fov;mvp[5]=uy*fov;mvp[6]=uz*fov;mvp[7]=0;
|
||||
mvp[8]=fx;mvp[9]=fy;mvp[10]=fz;mvp[11]=0;
|
||||
mvp[12]=-(rx*ex+ry*ey+rz*ez)*fov/asp;
|
||||
mvp[13]=-(ux*ex+uy*ey+uz*ez)*fov;
|
||||
mvp[14]=-(fx*ex+fy*ey+fz*ez);mvp[15]=1;
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs=NULL;
|
||||
g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState* dss=NULL;
|
||||
g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
|
||||
// 地面
|
||||
shader_set_matrix(g_shader, ctx, mvp);
|
||||
draw_quad_3d(ctx, -5, 0, 10, 10, 0.3f, 0.35f, 0.4f, 1);
|
||||
|
||||
// 场景节点
|
||||
for (int i=0;i<g_scene.node_count;i++) {
|
||||
SceneNode*n=&g_scene.nodes[i];
|
||||
if (!n->visible||n->id==0||n->user_type!=1) continue;
|
||||
// 用世界矩阵变换4个角点
|
||||
float corners[4][3] = {{-0.5f,-0.5f,0},{0.5f,-0.5f,0},{0.5f,0.5f,0},{-0.5f,0.5f,0}};
|
||||
V v[4]; uint32_t idx[6]={0,1,2,0,2,3};
|
||||
float colors[][3]={{1,0.2f,0.2f},{0.2f,1,0.2f},{0.2f,0.2f,1},{1,1,0.2f},{0.5f,0.2f,0.8f},{0.2f,0.8f,0.8f},{0.8f,0.5f,0.2f},{0.5f,0.5f,0.5f}};
|
||||
int ci=(i-1)%8;
|
||||
for(int c=0;c<4;c++){
|
||||
float px=0,py=0,pz=0;
|
||||
for(int r=0;r<4;r++) {float wc=n->world_matrix.m[0][r]*corners[c][0]+n->world_matrix.m[1][r]*corners[c][1]+n->world_matrix.m[2][r]*corners[c][2]+n->world_matrix.m[3][r]; px+=wc*mvp[r*4+0]; py+=wc*mvp[r*4+1]; pz+=wc*mvp[r*4+2];}
|
||||
// 简化: 直接用世界坐标+投影
|
||||
float wx=n->world_matrix.m[3][0]+corners[c][0];
|
||||
float wy=n->world_matrix.m[3][1]+corners[c][1];
|
||||
float wz=n->world_matrix.m[3][2]+corners[c][2];
|
||||
v[c].p[0]=wx; v[c].p[1]=wy; v[c].p[2]=wz;
|
||||
v[c].n[0]=0; v[c].n[1]=0; v[c].n[2]=1;
|
||||
v[c].c[0]=colors[ci][0]; v[c].c[1]=colors[ci][1]; v[c].c[2]=colors[ci][2]; v[c].c[3]=1;
|
||||
}
|
||||
ID3D11Buffer* vb=NULL,*ib2=NULL;
|
||||
D3D11_BUFFER_DESC bd2={}; D3D11_SUBRESOURCE_DATA sd2={};
|
||||
bd2.ByteWidth=sizeof(V)*4; bd2.Usage=D3D11_USAGE_DEFAULT; bd2.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd2.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&vb);
|
||||
bd2.ByteWidth=sizeof(uint32_t)*6; bd2.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd2.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&ib2);
|
||||
UINT s2=sizeof(V),o2=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o2);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib2,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib2->lpVtbl->Release(ib2); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
if(rs) rs->lpVtbl->Release(rs);
|
||||
if(dss) dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if (key==VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) {
|
||||
EngineConfig cfg=engine_default_config(); cfg.app_name="lity3d Raw3D";
|
||||
Engine* e=engine_create(); if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
g_shader=shader_create(); shader_compile(g_shader,g_dev->device,NULL,NULL,0,0);
|
||||
scene_init(&g_scene);
|
||||
SceneNode* c1=scene_create_node(&g_scene,"Cube1"); scene_set_position(c1,0,0.5f,0); c1->user_type=1;
|
||||
SceneNode* c2=scene_create_node(&g_scene,"Cube2"); scene_set_position(c2,-3,0.5f,2); c2->user_type=1;
|
||||
SceneNode* c3=scene_create_node(&g_scene,"Cube3"); scene_set_position(c3,3,0.5f,-2); scene_set_scale(c3,0.5f,0.5f,0.5f); c3->user_type=1;
|
||||
SceneNode* ch=scene_create_node(&g_scene,"Child"); scene_set_position(ch,2,0,0); ch->user_type=1; scene_set_parent(ch,c1);
|
||||
engine_set_render_callback(e,on_render); engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
shader_destroy(g_shader); graphics_device_destroy(g_dev); engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// scene_test.c - 场景图 + 网格渲染
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Rendering/mesh.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static Mesh* g_cube = NULL;
|
||||
static Mesh* g_plane = NULL;
|
||||
static Scene g_scene;
|
||||
static SceneNode* g_camera = NULL;
|
||||
static float g_time = 0;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
scene_update(&g_scene);
|
||||
g_time += (float)engine->delta_time;
|
||||
|
||||
float sw = (float)g_dev->width, sh = (float)g_dev->height;
|
||||
float fov = 1.0f / tanf(0.5f * 0.785f), aspect = sw / sh;
|
||||
Vec3 cam_pos;
|
||||
scene_get_world_position(g_camera, &cam_pos);
|
||||
|
||||
// VP 矩阵
|
||||
float proj[16] = {0};
|
||||
proj[0] = fov / aspect; proj[5] = -fov;
|
||||
proj[10] = 1.0f; proj[11] = -1.0f; proj[14] = 0.1f; proj[15] = 1.0f;
|
||||
|
||||
Vec3 eye = cam_pos, target = {0,0,0}, up = {0,1,0};
|
||||
Vec3 f, r, u;
|
||||
vec3_sub(&target, &eye, &f); vec3_normalize(&f, &f);
|
||||
vec3_cross(&up, &f, &r); vec3_normalize(&r, &r);
|
||||
vec3_cross(&f, &r, &u);
|
||||
|
||||
float view[16] = {0};
|
||||
view[0]=r.x; view[1]=u.x; view[2]=-f.x;
|
||||
view[4]=r.y; view[5]=u.y; view[6]=-f.y;
|
||||
view[8]=r.z; view[9]=u.z; view[10]=-f.z;
|
||||
view[12]=-vec3_dot(&r,&eye); view[13]=-vec3_dot(&u,&eye); view[14]=vec3_dot(&f,&eye); view[15]=1.0f;
|
||||
|
||||
float vp_raw[16] = {0};
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
vp_raw[i*4+j] = view[i*4+0]*proj[0*4+j]+view[i*4+1]*proj[1*4+j]+view[i*4+2]*proj[2*4+j]+view[i*4+3]*proj[3*4+j];
|
||||
Mat4 vp_m, vp_t;
|
||||
memcpy(&vp_m, vp_raw, sizeof(Mat4));
|
||||
mat4_transpose(&vp_m, &vp_t);
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
|
||||
D3D11_VIEWPORT vport = {0}; vport.Width = sw; vport.Height = sh; vport.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
|
||||
|
||||
D3D11_RASTERIZER_DESC rdesc = {0}; rdesc.FillMode = D3D11_FILL_SOLID; rdesc.CullMode = D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rstate = NULL;
|
||||
g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device, &rdesc, &rstate);
|
||||
ctx->lpVtbl->RSSetState(ctx, rstate);
|
||||
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&vp_t);
|
||||
|
||||
if (g_plane) mesh_draw(g_plane, ctx);
|
||||
|
||||
for (int i = 0; i < g_scene.node_count; i++) {
|
||||
SceneNode* node = &g_scene.nodes[i];
|
||||
if (!node->visible || node->id == 0 || node->user_type != 1 || !g_cube) continue;
|
||||
float wvp_raw[16] = {0};
|
||||
for (int r2 = 0; r2 < 4; r2++)
|
||||
for (int c = 0; c < 4; c++)
|
||||
wvp_raw[r2*4+c] = view[r2*4+0]*node->world_matrix.m[0][c]+view[r2*4+1]*node->world_matrix.m[1][c]+view[r2*4+2]*node->world_matrix.m[2][c]+view[r2*4+3]*node->world_matrix.m[3][c];
|
||||
Mat4 wvp_m, wvp_t;
|
||||
memcpy(&wvp_m, wvp_raw, sizeof(Mat4));
|
||||
mat4_transpose(&wvp_m, &wvp_t);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&wvp_t);
|
||||
mesh_draw(g_cube, ctx);
|
||||
}
|
||||
|
||||
if (rstate) rstate->lpVtbl->Release(rstate);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if (key == VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) {
|
||||
(void)hI;(void)hP;(void)cmd;(void)nS;
|
||||
EngineConfig cfg = engine_default_config();
|
||||
cfg.app_name = "lity3d Scene Test";
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &cfg)) return -1;
|
||||
g_dev = graphics_device_create();
|
||||
if (!graphics_device_init(g_dev, window_get_handle(engine->window), cfg.window_width, cfg.window_height, 1)) return -1;
|
||||
g_shader = shader_create();
|
||||
shader_compile(g_shader, g_dev->device, NULL, NULL, 0, 0);
|
||||
g_cube = mesh_create_cube(g_dev->device);
|
||||
g_plane = mesh_create_plane(g_dev->device, 10.0f);
|
||||
scene_init(&g_scene);
|
||||
g_camera = scene_create_node(&g_scene, "Camera");
|
||||
scene_set_position(g_camera, 5, 4, 8);
|
||||
SceneNode* c1 = scene_create_node(&g_scene, "Cube1");
|
||||
scene_set_position(c1, 0, 0.5f, 0); c1->user_type = 1;
|
||||
SceneNode* c2 = scene_create_node(&g_scene, "Cube2");
|
||||
scene_set_position(c2, -3, 0.5f, 2); c2->user_type = 1;
|
||||
SceneNode* c3 = scene_create_node(&g_scene, "Cube3");
|
||||
scene_set_position(c3, 3, 0.5f, -2); c3->user_type = 1; scene_set_scale(c3, 0.5f, 0.5f, 0.5f);
|
||||
SceneNode* child = scene_create_node(&g_scene, "Child");
|
||||
scene_set_position(child, 2, 0, 0); child->user_type = 1; scene_set_parent(child, c1);
|
||||
engine_set_render_callback(engine, on_render);
|
||||
engine_set_key_callback(engine, on_key);
|
||||
engine_run(engine);
|
||||
mesh_destroy(g_cube); mesh_destroy(g_plane); shader_destroy(g_shader);
|
||||
graphics_device_destroy(g_dev); engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// scene_test2.c - 最小化场景测试
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
float clear[4] = {0.2f, 0.3f, 0.5f, 1.0f};
|
||||
g_dev->context->lpVtbl->ClearRenderTargetView(g_dev->context, g_dev->render_target, clear);
|
||||
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = (float)g_dev->width; vp.Height = (float)g_dev->height;
|
||||
vp.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) {
|
||||
(void)hI;(void)hP;(void)cmd;(void)nS;
|
||||
LOG_INFO("=== lity3d Scene Test ===");
|
||||
EngineConfig cfg = engine_default_config();
|
||||
cfg.app_name = "lity3d Scene Test";
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &cfg)) return -1;
|
||||
g_dev = graphics_device_create();
|
||||
if (!graphics_device_init(g_dev, window_get_handle(engine->window), cfg.window_width, cfg.window_height, 1)) return -1;
|
||||
LOG_INFO("D3D11 ready");
|
||||
Scene scene; scene_init(&scene);
|
||||
SceneNode* n1 = scene_create_node(&scene, "A");
|
||||
scene_set_position(n1, 1, 0, 0);
|
||||
SceneNode* n2 = scene_create_node(&scene, "B");
|
||||
scene_set_parent(n2, n1);
|
||||
scene_set_position(n2, 0, 2, 0);
|
||||
scene_update(&scene);
|
||||
LOG_INFO("A world pos: (%.1f,%.1f,%.1f)", scene.nodes[1].world_matrix.m[3][0], scene.nodes[1].world_matrix.m[3][1], scene.nodes[1].world_matrix.m[3][2]);
|
||||
LOG_INFO("B world pos: (%.1f,%.1f,%.1f)", scene.nodes[2].world_matrix.m[3][0], scene.nodes[2].world_matrix.m[3][1], scene.nodes[2].world_matrix.m[3][2]);
|
||||
engine_set_render_callback(engine, on_render);
|
||||
engine_set_key_callback(engine, on_key);
|
||||
engine_run(engine);
|
||||
graphics_device_destroy(g_dev);
|
||||
engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# lity3d 积木脚本 - 测试解释器
|
||||
# 开始 -> 移动物体 -> 打印 -> 循环3次 -> 移动物体
|
||||
|
||||
[B]
|
||||
id=1
|
||||
name=开始
|
||||
p=100,100
|
||||
c=0
|
||||
|
||||
[B]
|
||||
id=2
|
||||
name=移动物体
|
||||
p=350,100
|
||||
c=1
|
||||
|
||||
[B]
|
||||
id=3
|
||||
name=打印
|
||||
p=600,100
|
||||
d=Hello World
|
||||
c=3
|
||||
|
||||
[B]
|
||||
id=4
|
||||
name=循环
|
||||
p=100,250
|
||||
d=3
|
||||
c=2
|
||||
|
||||
[B]
|
||||
id=5
|
||||
name=移动物体
|
||||
p=350,250
|
||||
c=1
|
||||
|
||||
# 连线: 开始.输出0 -> 移动物体.执行0
|
||||
[W]
|
||||
a=10000
|
||||
b=20000
|
||||
|
||||
# 移动物体.执行0 -> 打印.执行0
|
||||
[W]
|
||||
a=20000
|
||||
b=30000
|
||||
|
||||
# 打印.执行0 -> 循环.执行0
|
||||
[W]
|
||||
a=30000
|
||||
b=40000
|
||||
|
||||
# 循环.执行0 -> 移动物体2.执行0
|
||||
[W]
|
||||
a=40000
|
||||
b=50000
|
||||
@@ -0,0 +1,118 @@
|
||||
// ============================================================================
|
||||
// audio_demo.c - XAudio2 音频系统演示
|
||||
// 生成 440Hz 正弦波并播放 2 秒,无需外部 WAV 文件
|
||||
// ============================================================================
|
||||
|
||||
#include "../Engine/Audio/audio.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <windows.h>
|
||||
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
|
||||
// 生成标准 PCM WAV 数据 (44.1kHz, 16bit, 单声道)
|
||||
static uint8_t* generate_sine_wave_wav(float frequency, float duration_sec, uint32_t* out_size) {
|
||||
const uint32_t sample_rate = 44100;
|
||||
const uint16_t channels = 1;
|
||||
const uint16_t bits_per_sample = 16;
|
||||
const uint16_t block_align = channels * bits_per_sample / 8;
|
||||
const uint32_t byte_rate = sample_rate * block_align;
|
||||
const uint32_t num_samples = (uint32_t)(sample_rate * duration_sec);
|
||||
const uint32_t data_size = num_samples * block_align;
|
||||
const uint32_t file_size = 44 + data_size;
|
||||
|
||||
uint8_t* wav = (uint8_t*)malloc(file_size);
|
||||
if (!wav) return NULL;
|
||||
|
||||
// RIFF 头
|
||||
memcpy(wav + 0, "RIFF", 4);
|
||||
memcpy(wav + 4, &file_size, 4);
|
||||
memcpy(wav + 8, "WAVE", 4);
|
||||
|
||||
// fmt chunk
|
||||
memcpy(wav + 12, "fmt ", 4);
|
||||
uint32_t fmt_size = 16;
|
||||
memcpy(wav + 16, &fmt_size, 4);
|
||||
uint16_t audio_format = 1; // PCM
|
||||
memcpy(wav + 20, &audio_format, 2);
|
||||
memcpy(wav + 22, &channels, 2);
|
||||
memcpy(wav + 24, &sample_rate, 4);
|
||||
memcpy(wav + 28, &byte_rate, 4);
|
||||
memcpy(wav + 32, &block_align, 2);
|
||||
memcpy(wav + 34, &bits_per_sample, 2);
|
||||
|
||||
// data chunk
|
||||
memcpy(wav + 36, "data", 4);
|
||||
memcpy(wav + 40, &data_size, 4);
|
||||
|
||||
// 生成正弦波样本
|
||||
int16_t* samples = (int16_t*)(wav + 44);
|
||||
float amplitude = 0.3f; // 避免削波
|
||||
for (uint32_t i = 0; i < num_samples; i++) {
|
||||
float t = (float)i / (float)sample_rate;
|
||||
// 简单淡出,避免咔嗒声
|
||||
float envelope = 1.0f;
|
||||
if (i < 1000) envelope = (float)i / 1000.0f;
|
||||
if (i > num_samples - 1000) envelope = (float)(num_samples - i) / 1000.0f;
|
||||
float sample = sinf(2.0f * 3.14159265f * frequency * t) * amplitude * envelope;
|
||||
samples[i] = (int16_t)(sample * 32767.0f);
|
||||
}
|
||||
|
||||
*out_size = file_size;
|
||||
return wav;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
(void)argc; (void)argv;
|
||||
|
||||
printf("Lity3D - Audio Demo\n");
|
||||
printf("========================\n");
|
||||
|
||||
AudioSystem* audio = audio_create();
|
||||
if (!audio) {
|
||||
printf("ERROR: Failed to create XAudio2 audio system\n");
|
||||
return 1;
|
||||
}
|
||||
printf("XAudio2 audio system created.\n");
|
||||
|
||||
AudioSource* source = audio_source_create(audio);
|
||||
if (!source) {
|
||||
printf("ERROR: Failed to create audio source\n");
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t wav_size = 0;
|
||||
uint8_t* wav_data = generate_sine_wave_wav(440.0f, 2.0f, &wav_size);
|
||||
if (!wav_data) {
|
||||
printf("ERROR: Failed to generate sine wave\n");
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!audio_load_wav_memory(source, wav_data, wav_size)) {
|
||||
printf("ERROR: Failed to load generated WAV into audio source\n");
|
||||
free(wav_data);
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
return 1;
|
||||
}
|
||||
free(wav_data);
|
||||
printf("Generated 440Hz sine wave loaded.\n");
|
||||
|
||||
printf("Playing 2 seconds...\n");
|
||||
audio_source_play(source);
|
||||
|
||||
// 等待播放结束 (约 2 秒 + 缓冲)
|
||||
Sleep(2500);
|
||||
|
||||
audio_source_destroy(source);
|
||||
audio_destroy(audio);
|
||||
|
||||
printf("Audio demo finished successfully.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
static ID3D11Device* g_dev; static ID3D11DeviceContext* g_ctx;
|
||||
static IDXGISwapChain* g_sc; static ID3D11RenderTargetView* g_rtv;
|
||||
static ID3D11VertexShader* g_vs; static ID3D11PixelShader* g_ps;
|
||||
static ID3D11InputLayout* g_il; static ID3D11Buffer* g_cb;
|
||||
|
||||
static int key_l=0,key_r=0,key_u=0,key_d=0,key_sp=0;
|
||||
static int dead=0, score=0;
|
||||
static float px=0, py=0, speed=0.4f;
|
||||
#define NOBS 15
|
||||
static float ox[NOBS],oy[NOBS],oz[NOBS],osz[NOBS];
|
||||
static int oa[NOBS],oc=0; static float st=0;
|
||||
|
||||
static void Init(HWND h){
|
||||
HRESULT hr;DXGI_SWAP_CHAIN_DESC sd;memset(&sd,0,sizeof(sd));sd.BufferCount=2;sd.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;sd.BufferDesc.RefreshRate.Numerator=60;sd.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;sd.OutputWindow=h;sd.SampleDesc.Count=1;sd.Windowed=TRUE;sd.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_11_0,gt;hr=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,&fl,1,D3D11_SDK_VERSION,&sd,&g_sc,&g_dev,>,&g_ctx);if(FAILED(hr))return;
|
||||
ID3D11Texture2D*bb=NULL;hr=g_sc->lpVtbl->GetBuffer(g_sc,0,&IID_ID3D11Texture2D,(void**)&bb);if(FAILED(hr)||!bb)return;hr=g_dev->lpVtbl->CreateRenderTargetView(g_dev,(ID3D11Resource*)bb,NULL,&g_rtv);bb->lpVtbl->Release(bb);if(FAILED(hr))return;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.c=i.c;return o;}";
|
||||
const char*ps="float4 main(float4 p:SV_POSITION, float4 c:COLOR):SV_Target{return c;}";
|
||||
ID3DBlob*b1,*b2,*e;D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);if(e){e->lpVtbl->Release(e);e=NULL;}D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);if(e){e->lpVtbl->Release(e);e=NULL;}if(!b1||!b2)return;
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);g_dev->lpVtbl->CreatePixelShader(g_dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];memset(el,0,sizeof(el));el[0].SemanticName="POSITION";el[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[1].SemanticName="NORMAL";el[1].AlignedByteOffset=12;el[1].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[2].SemanticName="TEXCOORD";el[2].AlignedByteOffset=24;el[2].Format=DXGI_FORMAT_R32G32_FLOAT;el[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[3].SemanticName="COLOR";el[3].AlignedByteOffset=32;el[3].Format=DXGI_FORMAT_R32G32B32A32_FLOAT;el[3].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev,el,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;memset(&cbd,0,sizeof(cbd));cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;g_dev->lpVtbl->CreateBuffer(g_dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void Cube(float cx,float cy,float cz,float s,float cr,float cg,float cb){
|
||||
V3D v[24];float f[6][4][3]={{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}};float nm[6][3]={{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for(int fi=0;fi<6;fi++)for(int vi=0;vi<4;vi++){int i=fi*4+vi;v[i].p[0]=f[fi][vi][0]*s+cx;v[i].p[1]=f[fi][vi][1]*s+cy;v[i].p[2]=f[fi][vi][2]*s+cz;v[i].n[0]=nm[fi][0];v[i].n[1]=nm[fi][1];v[i].n[2]=nm[fi][2];v[i].c[0]=cr;v[i].c[1]=cg;v[i].c[2]=cb;v[i].c[3]=1;}
|
||||
uint32_t ix[36];for(int fi=0;fi<6;fi++){int b=fi*4;ix[fi*6]=b;ix[fi*6+1]=b+1;ix[fi*6+2]=b+2;ix[fi*6+3]=b;ix[fi*6+4]=b+2;ix[fi*6+5]=b+3;}
|
||||
ID3D11Buffer*vb,*ib;D3D11_BUFFER_DESC bd;D3D11_SUBRESOURCE_DATA sd;memset(&bd,0,sizeof(bd));memset(&sd,0,sizeof(sd));bd.ByteWidth=sizeof(V3D)*24;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;sd.pSysMem=v;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&vb);bd.ByteWidth=sizeof(uint32_t)*36;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;sd.pSysMem=ix;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V3D),o=0;g_ctx->lpVtbl->IASetVertexBuffers(g_ctx,0,1,&vb,&s2,&o);g_ctx->lpVtbl->IASetIndexBuffer(g_ctx,ib,DXGI_FORMAT_R32_UINT,0);g_ctx->lpVtbl->DrawIndexed(g_ctx,36,0,0);ib->lpVtbl->Release(ib);vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void Spawn(void){for(int i=0;i<NOBS;i++){if(!oa[i]){oa[i]=1;ox[i]=-1.0f+(float)(rand()%200)/100.0f;oy[i]=-0.6f+(float)(rand()%120)/100.0f;oz[i]=1.95f;osz[i]=0.08f+(float)(rand()%80)/400.0f;oc++;return;}}}
|
||||
|
||||
static void Frame(void){
|
||||
float dt=0.016f,spd=speed*dt;
|
||||
if(dead){if(key_sp){dead=0;score=0;speed=0.4f;px=py=0;oc=0;st=0;for(int i=0;i<NOBS;i++)oa[i]=0;}}
|
||||
else{
|
||||
if(key_l)px-=spd;if(key_r)px+=spd;if(key_u)py+=spd;if(key_d)py-=spd;
|
||||
if(px<-1.3f)px=-1.3f;if(px>1.3f)px=1.3f;if(py<-0.9f)py=-0.9f;if(py>0.9f)py=0.9f;
|
||||
st+=dt;if(st>0.6f/speed){Spawn();st=0;}
|
||||
for(int i=0;i<NOBS;i++){
|
||||
if(!oa[i])continue;oz[i]-=speed*dt;
|
||||
if(oz[i]<1.0f){oa[i]=0;oc--;score++;speed=0.4f+score*0.05f;if(speed>2.0f)speed=2.0f;}
|
||||
float dx=px>ox[i]?px-ox[i]:ox[i]-px;float dy=py>oy[i]?py-oy[i]:oy[i]-py;float dz=1.5f>oz[i]?1.5f-oz[i]:oz[i]-1.5f;
|
||||
float md=0.12f+osz[i];if(dx<md&&dy<md&&dz<md)dead=1;
|
||||
}
|
||||
}
|
||||
|
||||
float fov=1.0f/tanf(0.4f),asp=1280.0f/720.0f;
|
||||
float mvp[16];memset(mvp,0,sizeof(mvp));
|
||||
mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
|
||||
float cl[4]={.08f,.1f,.14f,1};if(dead){cl[0]=.12f;cl[1]=.02f;cl[2]=.02f;}
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx,1,&g_rtv,NULL);g_ctx->lpVtbl->ClearRenderTargetView(g_ctx,g_rtv,cl);
|
||||
D3D11_VIEWPORT vp;memset(&vp,0,sizeof(vp));vp.Width=1280;vp.Height=720;vp.MaxDepth=1;g_ctx->lpVtbl->RSSetViewports(g_ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd;memset(&rd,0,sizeof(rd));rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;ID3D11RasterizerState*rs;g_dev->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);g_ctx->lpVtbl->RSSetState(g_ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds;memset(&ds,0,sizeof(ds));ds.DepthEnable=FALSE;ID3D11DepthStencilState*dss;g_dev->lpVtbl->CreateDepthStencilState(g_dev,&ds,&dss);g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx,dss,0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);g_ctx->lpVtbl->VSSetShader(g_ctx,g_vs,NULL,0);g_ctx->lpVtbl->PSSetShader(g_ctx,g_ps,NULL,0);g_ctx->lpVtbl->IASetInputLayout(g_ctx,g_il);g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx,0,1,&g_cb);g_ctx->lpVtbl->UpdateSubresource(g_ctx,(ID3D11Resource*)g_cb,0,NULL,mvp,0,0);
|
||||
|
||||
if(dead){Cube(0,0,1.5f,0.4f,.9f,.1f,.1f);}
|
||||
else{
|
||||
Cube(px,py,1.5f,0.12f,.1f,.9f,.3f);
|
||||
for(int i=0;i<NOBS;i++){if(!oa[i])continue;float fl=.6f+.4f*sinf(oz[i]*8.0f);Cube(ox[i],oy[i],oz[i],osz[i],fl,.15f,.1f);}
|
||||
}
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);g_sc->lpVtbl->Present(g_sc,1,0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h,UINT m,WPARAM w,LPARAM l){switch(m){case WM_KEYDOWN:switch(w){case VK_LEFT:key_l=1;break;case VK_RIGHT:key_r=1;break;case VK_UP:key_u=1;break;case VK_DOWN:key_d=1;break;case 'A':key_l=1;break;case 'D':key_r=1;break;case 'W':key_u=1;break;case 'S':key_d=1;break;case VK_SPACE:key_sp=1;break;case VK_ESCAPE:PostQuitMessage(0);break;}break;case WM_KEYUP:switch(w){case VK_LEFT:key_l=0;break;case VK_RIGHT:key_r=0;break;case VK_UP:key_u=0;break;case VK_DOWN:key_d=0;break;case 'A':key_l=0;break;case 'D':key_r=0;break;case 'W':key_u=0;break;case 'S':key_d=0;break;case VK_SPACE:key_sp=0;break;}break;case WM_DESTROY:PostQuitMessage(0);return 0;}return DefWindowProcW(h,m,w,l);}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){srand(42);WNDCLASSEXW wc;memset(&wc,0,sizeof(wc));wc.cbSize=sizeof(wc);wc.style=CS_CLASSDC;wc.lpfnWndProc=WP;wc.hInstance=hI;wc.lpszClassName=L"dodge";RegisterClassExW(&wc);HWND hwnd=CreateWindowW(L"dodge",L"Cube Dodge - WASD/Arrows move, Space restart",WS_OVERLAPPEDWINDOW,200,100,1280,720,NULL,NULL,hI,NULL);if(!hwnd)return -1;ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);Init(hwnd);MSG msg;while(1){while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);if(msg.message==WM_QUIT)goto done;}Frame();}done:if(g_cb)g_cb->lpVtbl->Release(g_cb);if(g_il)g_il->lpVtbl->Release(g_il);if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_rtv)g_rtv->lpVtbl->Release(g_rtv);if(g_sc)g_sc->lpVtbl->Release(g_sc);if(g_ctx)g_ctx->lpVtbl->Release(g_ctx);if(g_dev)g_dev->lpVtbl->Release(g_dev);return 0;}
|
||||
@@ -0,0 +1,222 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
|
||||
static ID3D11Device* g_dev = NULL;
|
||||
static ID3D11DeviceContext* g_ctx = NULL;
|
||||
static IDXGISwapChain* g_sc = NULL;
|
||||
static ID3D11RenderTargetView* g_rtv = NULL;
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
|
||||
static float cam_x = 0, cam_z = 0;
|
||||
static int key_w = 0, key_s = 0, key_a = 0, key_d = 0;
|
||||
static int key_left = 0, key_right = 0;
|
||||
static int sel = 0;
|
||||
|
||||
static void Init(HWND h) {
|
||||
HRESULT hr;
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
memset(&sd, 0, sizeof(sd));
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = h;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl = D3D_FEATURE_LEVEL_11_0;
|
||||
D3D_FEATURE_LEVEL got;
|
||||
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &fl, 1,
|
||||
D3D11_SDK_VERSION, &sd, &g_sc, &g_dev, &got, &g_ctx);
|
||||
if (FAILED(hr)) { return; }
|
||||
ID3D11Texture2D* bb = NULL;
|
||||
hr = g_sc->lpVtbl->GetBuffer(g_sc, 0, &IID_ID3D11Texture2D, (void**)&bb);
|
||||
if (FAILED(hr) || !bb) { return; }
|
||||
hr = g_dev->lpVtbl->CreateRenderTargetView(g_dev, (ID3D11Resource*)bb, NULL, &g_rtv);
|
||||
bb->lpVtbl->Release(bb);
|
||||
if (FAILED(hr)) { return; }
|
||||
const char* vs_src =
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"struct O{float4 p:SV_POSITION;float4 c:COLOR;};"
|
||||
"O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.c=i.c;return o;}";
|
||||
const char* ps_src =
|
||||
"float4 main(float4 pos:SV_POSITION, float4 col:COLOR):SV_Target{return col;}";
|
||||
ID3DBlob *b1 = NULL, *b2 = NULL, *e1 = NULL, *e2 = NULL;
|
||||
D3DCompile(vs_src, (UINT)strlen(vs_src), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &b1, &e1);
|
||||
if (e1) { e1->lpVtbl->Release(e1); e1 = NULL; }
|
||||
D3DCompile(ps_src, (UINT)strlen(ps_src), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &b2, &e2);
|
||||
if (e2) { e2->lpVtbl->Release(e2); e2 = NULL; }
|
||||
if (!b1 || !b2) { return; }
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), NULL, &g_vs);
|
||||
g_dev->lpVtbl->CreatePixelShader(g_dev, b2->lpVtbl->GetBufferPointer(b2), b2->lpVtbl->GetBufferSize(b2), NULL, &g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];
|
||||
memset(el, 0, sizeof(el));
|
||||
el[0].SemanticName = "POSITION"; el[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[1].SemanticName = "NORMAL"; el[1].AlignedByteOffset = 12; el[1].Format = DXGI_FORMAT_R32G32B32_FLOAT; el[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[2].SemanticName = "TEXCOORD"; el[2].AlignedByteOffset = 24; el[2].Format = DXGI_FORMAT_R32G32_FLOAT; el[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
el[3].SemanticName = "COLOR"; el[3].AlignedByteOffset = 32; el[3].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; el[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev, el, 4, b1->lpVtbl->GetBufferPointer(b1), b1->lpVtbl->GetBufferSize(b1), &g_il);
|
||||
b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;
|
||||
memset(&cbd, 0, sizeof(cbd));
|
||||
cbd.ByteWidth = 256; cbd.Usage = D3D11_USAGE_DEFAULT; cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
||||
g_dev->lpVtbl->CreateBuffer(g_dev, &cbd, NULL, &g_cb);
|
||||
}
|
||||
|
||||
static void DrawCube(float cx, float cy, float cz, float s, float cr, float cg, float cb2) {
|
||||
V3D v[24];
|
||||
float f[6][4][3] = {
|
||||
{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},
|
||||
{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},
|
||||
{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},
|
||||
{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},
|
||||
{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},
|
||||
{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}
|
||||
};
|
||||
float nm[6][3] = {{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for (int fi = 0; fi < 6; fi++)
|
||||
for (int vi = 0; vi < 4; vi++) {
|
||||
int i = fi * 4 + vi;
|
||||
v[i].p[0] = f[fi][vi][0] * s + cx;
|
||||
v[i].p[1] = f[fi][vi][1] * s + cy;
|
||||
v[i].p[2] = f[fi][vi][2] * s + cz;
|
||||
v[i].n[0] = nm[fi][0]; v[i].n[1] = nm[fi][1]; v[i].n[2] = nm[fi][2];
|
||||
v[i].c[0] = cr; v[i].c[1] = cg; v[i].c[2] = cb2; v[i].c[3] = 1;
|
||||
}
|
||||
uint32_t ix[36];
|
||||
for (int fi = 0; fi < 6; fi++) {
|
||||
int b = fi * 4;
|
||||
ix[fi*6]=b; ix[fi*6+1]=b+1; ix[fi*6+2]=b+2; ix[fi*6+3]=b; ix[fi*6+4]=b+2; ix[fi*6+5]=b+3;
|
||||
}
|
||||
ID3D11Buffer *vb = NULL, *ib = NULL;
|
||||
D3D11_BUFFER_DESC bd; D3D11_SUBRESOURCE_DATA sd;
|
||||
memset(&bd, 0, sizeof(bd)); memset(&sd, 0, sizeof(sd));
|
||||
bd.ByteWidth = sizeof(V3D) * 24; bd.Usage = D3D11_USAGE_DEFAULT; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem = v; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &vb);
|
||||
bd.ByteWidth = sizeof(uint32_t) * 36; bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem = ix; g_dev->lpVtbl->CreateBuffer(g_dev, &bd, &sd, &ib);
|
||||
UINT s2 = sizeof(V3D), o = 0;
|
||||
g_ctx->lpVtbl->IASetVertexBuffers(g_ctx, 0, 1, &vb, &s2, &o);
|
||||
g_ctx->lpVtbl->IASetIndexBuffer(g_ctx, ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
g_ctx->lpVtbl->DrawIndexed(g_ctx, 36, 0, 0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void Frame(void) {
|
||||
float dt = 0.016f, spd = 3.0f * dt;
|
||||
if (key_w) cam_z += spd; if (key_s) cam_z -= spd;
|
||||
if (key_a) cam_x -= spd; if (key_d) cam_x += spd;
|
||||
if (key_left) sel = (sel + 3) % 4;
|
||||
if (key_right) sel = (sel + 1) % 4;
|
||||
|
||||
float fov = 1.0f / tanf(0.4f), asp = 1280.0f / 720.0f;
|
||||
float mvp[16]; memset(mvp, 0, sizeof(mvp));
|
||||
mvp[0] = fov / asp; mvp[5] = -fov; mvp[10] = 1; mvp[11] = -1; mvp[14] = 0.1f; mvp[15] = 1;
|
||||
float m2[16]; memcpy(m2, mvp, 64);
|
||||
for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { float t = m2[i*4+j]; m2[i*4+j] = m2[j*4+i]; m2[j*4+i] = t; }
|
||||
|
||||
float cl[4] = {.15f, .18f, .25f, 1};
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx, 1, &g_rtv, NULL);
|
||||
g_ctx->lpVtbl->ClearRenderTargetView(g_ctx, g_rtv, cl);
|
||||
D3D11_VIEWPORT vp; memset(&vp, 0, sizeof(vp));
|
||||
vp.Width = 1280; vp.Height = 720; vp.MaxDepth = 1;
|
||||
g_ctx->lpVtbl->RSSetViewports(g_ctx, 1, &vp);
|
||||
D3D11_RASTERIZER_DESC rd; memset(&rd, 0, sizeof(rd));
|
||||
rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs = NULL;
|
||||
g_dev->lpVtbl->CreateRasterizerState(g_dev, &rd, &rs);
|
||||
g_ctx->lpVtbl->RSSetState(g_ctx, rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds; memset(&ds, 0, sizeof(ds));
|
||||
ds.DepthEnable = FALSE;
|
||||
ID3D11DepthStencilState* dss = NULL;
|
||||
g_dev->lpVtbl->CreateDepthStencilState(g_dev, &ds, &dss);
|
||||
g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx, dss, 0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
g_ctx->lpVtbl->VSSetShader(g_ctx, g_vs, NULL, 0);
|
||||
g_ctx->lpVtbl->PSSetShader(g_ctx, g_ps, NULL, 0);
|
||||
g_ctx->lpVtbl->IASetInputLayout(g_ctx, g_il);
|
||||
g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx, 0, 1, &g_cb);
|
||||
g_ctx->lpVtbl->UpdateSubresource(g_ctx, (ID3D11Resource*)g_cb, 0, NULL, m2, 0, 0);
|
||||
|
||||
float colors[4][3] = {{1,.3f,.3f},{.3f,1,.3f},{.3f,.3f,1},{.8f,.8f,.2f}};
|
||||
float sizes[4] = {0.3f, 0.25f, 0.2f, 0.35f};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float cr = colors[i][0], cg = colors[i][1], cb = colors[i][2];
|
||||
if (i == sel) { cr = 1; cg = 1; cb = 1; }
|
||||
DrawCube(-0.8f + i * 0.6f - cam_x, 0, 1.5f - cam_z, sizes[i], cr, cg, cb);
|
||||
}
|
||||
|
||||
if (rs) rs->lpVtbl->Release(rs);
|
||||
if (dss) dss->lpVtbl->Release(dss);
|
||||
g_sc->lpVtbl->Present(g_sc, 1, 0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h, UINT m, WPARAM w, LPARAM l) {
|
||||
switch (m) {
|
||||
case WM_KEYDOWN:
|
||||
switch (w) {
|
||||
case 'W': key_w = 1; break; case 'S': key_s = 1; break;
|
||||
case 'A': key_a = 1; break; case 'D': key_d = 1; break;
|
||||
case VK_LEFT: key_left = 1; break; case VK_RIGHT: key_right = 1; break;
|
||||
case '1': sel = 0; break; case '2': sel = 1; break;
|
||||
case '3': sel = 2; break; case '4': sel = 3; break;
|
||||
case VK_ESCAPE: PostQuitMessage(0); break;
|
||||
}
|
||||
break;
|
||||
case WM_KEYUP:
|
||||
switch (w) {
|
||||
case 'W': key_w = 0; break; case 'S': key_s = 0; break;
|
||||
case 'A': key_a = 0; break; case 'D': key_d = 0; break;
|
||||
case VK_LEFT: key_left = 0; break; case VK_RIGHT: key_right = 0; break;
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY: PostQuitMessage(0); return 0;
|
||||
}
|
||||
return DefWindowProcW(h, m, w, l);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR nC, int nS) {
|
||||
(void)hP; (void)nC; (void)nS;
|
||||
WNDCLASSEXW wc;
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.style = CS_CLASSDC;
|
||||
wc.lpfnWndProc = WP;
|
||||
wc.hInstance = hI;
|
||||
wc.lpszClassName = L"game_test_cls";
|
||||
RegisterClassExW(&wc);
|
||||
HWND hwnd = CreateWindowW(L"game_test_cls", L"lity3d Game Test", WS_OVERLAPPEDWINDOW,
|
||||
100, 100, 1280, 720, NULL, NULL, hI, NULL);
|
||||
if (!hwnd) { MessageBoxA(NULL, "CreateWindow failed", "Error", MB_OK); return -1; }
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
Init(hwnd);
|
||||
MSG msg;
|
||||
while (1) {
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg); DispatchMessage(&msg);
|
||||
if (msg.message == WM_QUIT) goto done;
|
||||
}
|
||||
Frame();
|
||||
}
|
||||
done:
|
||||
if (g_cb) g_cb->lpVtbl->Release(g_cb);
|
||||
if (g_il) g_il->lpVtbl->Release(g_il);
|
||||
if (g_vs) g_vs->lpVtbl->Release(g_vs);
|
||||
if (g_ps) g_ps->lpVtbl->Release(g_ps);
|
||||
if (g_rtv) g_rtv->lpVtbl->Release(g_rtv);
|
||||
if (g_sc) g_sc->lpVtbl->Release(g_sc);
|
||||
if (g_ctx) g_ctx->lpVtbl->Release(g_ctx);
|
||||
if (g_dev) g_dev->lpVtbl->Release(g_dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
static float cam_x=0, cam_z=2, cam_yaw=0;
|
||||
static float mx=0, my=0;
|
||||
static int keys[256]={0};
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
static void draw_quad(ID3D11DeviceContext* ctx, float x, float y, float z, float s, float r, float g, float b) {
|
||||
V v[4]={{{x-s,y-s,z},{0,0,-1},{0,0},{r,g,b,1}},{{x+s,y-s,z},{0,0,-1},{1,0},{r,g,b,1}},
|
||||
{{x+s,y+s,z},{0,0,-1},{1,1},{r,g,b,1}},{{x-s,y+s,z},{0,0,-1},{0,1},{r,g,b,1}}};
|
||||
uint32_t idx[6]={0,1,2,0,2,3};
|
||||
ID3D11Buffer *vb=NULL,*ib=NULL; D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER; sd.pSysMem=idx;
|
||||
g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V),o=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if(!g_dev) return;
|
||||
ID3D11DeviceContext* ctx=g_dev->context;
|
||||
float dt=(float)engine->delta_time, sp=3.0f*dt;
|
||||
float fx=-sinf(cam_yaw),fz=-cosf(cam_yaw),rx=cosf(cam_yaw),rz=-sinf(cam_yaw);
|
||||
if(keys['W']){cam_x+=fx*sp;cam_z+=fz*sp;}
|
||||
if(keys['S']){cam_x-=fx*sp;cam_z-=fz*sp;}
|
||||
if(keys['A']){cam_x-=rx*sp;cam_z-=rz*sp;}
|
||||
if(keys['D']){cam_x+=rx*sp;cam_z+=rz*sp;}
|
||||
|
||||
float sw=(float)g_dev->width,sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f),asp=sw/sh;
|
||||
float mvp[16]={0}; mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
Mat4 pm,pt;memcpy(&pm,mvp,sizeof(Mat4));mat4_transpose(&pm,&pt);
|
||||
|
||||
graphics_device_clear(g_dev,0.12f,0.14f,0.18f,1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState*rs=NULL;g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState*dss=NULL;g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
ctx->lpVtbl->VSSetShader(ctx,g_vs,NULL,0);ctx->lpVtbl->PSSetShader(ctx,g_ps,NULL,0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx,g_il);ctx->lpVtbl->VSSetConstantBuffers(ctx,0,1,&g_cb);
|
||||
ctx->lpVtbl->UpdateSubresource(ctx,(ID3D11Resource*)g_cb,0,NULL,&pt,0,0);
|
||||
for(int x=-5;x<=5;x++)for(int z=-5;z<=5;z++){float c=((x+z)%2==0)?.4f:.3f;draw_quad(ctx,(float)x,(float)z,0.5f,0.5f,c,c,c);}
|
||||
draw_quad(ctx,0,0,0.5f,0.4f,1,0.3f,0.3f);draw_quad(ctx,2,0,0.5f,0.3f,.3f,1,.3f);draw_quad(ctx,-2,0,0.5f,0.3f,.3f,.3f,1);draw_quad(ctx,0,2,0.5f,0.5f,.8f,.8f,.2f);
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
static void on_key(Engine*e,int k){if(k>=0&&k<256)keys[k]=1;if(k==VK_ESCAPE)engine_request_quit(e);}
|
||||
static void on_mouse_move(int x,int y){cam_yaw+=(x-mx)*0.003f;mx=(float)x;my=(float)y;}
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){
|
||||
EngineConfig cfg=engine_default_config();cfg.app_name="lity3d Input Test";
|
||||
Engine*e=engine_create();if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
ID3DBlob*b1=NULL,*b2=NULL,*er=NULL;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
const char*ps="struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};float4 main(O i){return i.c;}";
|
||||
D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&er);if(er){er->lpVtbl->Release(er);er=NULL;}
|
||||
D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&er);if(er){er->lpVtbl->Release(er);er=NULL;}
|
||||
ID3D11Device*dev=g_dev->device;
|
||||
dev->lpVtbl->CreateVertexShader(dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);
|
||||
dev->lpVtbl->CreatePixelShader(dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC il[]={{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0}};
|
||||
dev->lpVtbl->CreateInputLayout(dev,il,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd={};cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;dev->lpVtbl->CreateBuffer(dev,&cbd,NULL,&g_cb);
|
||||
window_set_key_callback(e->window,on_key);window_set_mouse_move_callback(e->window,on_mouse_move);
|
||||
engine_set_render_callback(e,on_render);engine_run(e);
|
||||
if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_il)g_il->lpVtbl->Release(g_il);if(g_cb)g_cb->lpVtbl->Release(g_cb);
|
||||
graphics_device_destroy(g_dev);engine_shutdown(e);return 0;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
// light_test.c - 光照系统测试(基?raw3d_test 已验证模式)
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Rendering/lighting.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Light* g_sun = NULL;
|
||||
static float g_time = 0;
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
// 编译带光照的着色器
|
||||
static ID3D11VertexShader* g_vs = NULL;
|
||||
static ID3D11PixelShader* g_ps = NULL;
|
||||
static ID3D11InputLayout* g_il = NULL;
|
||||
static ID3D11Buffer* g_cb = NULL;
|
||||
|
||||
static const char* vs_src =
|
||||
"cbuffer CB:register(b0){float4x4 WVP;};"
|
||||
"struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};"
|
||||
"struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};"
|
||||
"O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
static const char* ps_src =
|
||||
"cbuffer Light:register(b1){float3 lightDir;float pad1;float3 lightColor;float intensity;float3 ambColor;float pad2;};"
|
||||
"struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};"
|
||||
"float4 main(O i):SV_TARGET{"
|
||||
"float3 n=normalize(i.n);"
|
||||
"float diff=max(dot(n,-normalize(lightDir)),0.0);"
|
||||
"float3 col=i.c.rgb*(ambColor+lightColor*diff*intensity);"
|
||||
"return float4(col,1.0);}";
|
||||
|
||||
static void InitShaders() {
|
||||
ID3DBlob *b1=NULL,*b2=NULL,*e=NULL;
|
||||
D3DCompile(vs_src,(UINT)strlen(vs_src),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);
|
||||
if(e){e->lpVtbl->Release(e);e=NULL;}
|
||||
D3DCompile(ps_src,(UINT)strlen(ps_src),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);
|
||||
if(e){e->lpVtbl->Release(e);e=NULL;}
|
||||
if(!b1||!b2) return;
|
||||
ID3D11Device* dev = g_dev->device;
|
||||
dev->lpVtbl->CreateVertexShader(dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);
|
||||
dev->lpVtbl->CreatePixelShader(dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC il[]={
|
||||
{"POSITION",0,DXGI_FORMAT_R32G32B32_FLOAT,0,0,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"NORMAL",0,DXGI_FORMAT_R32G32B32_FLOAT,0,12,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"TEXCOORD",0,DXGI_FORMAT_R32G32_FLOAT,0,24,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
{"COLOR",0,DXGI_FORMAT_R32G32B32A32_FLOAT,0,32,D3D11_INPUT_PER_VERTEX_DATA,0},
|
||||
};
|
||||
dev->lpVtbl->CreateInputLayout(dev,il,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);
|
||||
b1->lpVtbl->Release(b1); b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd={}; cbd.ByteWidth=256; cbd.Usage=D3D11_USAGE_DEFAULT;
|
||||
cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;
|
||||
dev->lpVtbl->CreateBuffer(dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void draw_lit_cube(ID3D11DeviceContext* ctx, ID3D11Device* dev, float cx, float cy, float cz, float s, float cr, float cg, float cb) {
|
||||
V v[24];
|
||||
float f[6][4][3]={{{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1}},{{1,-1,-1},{1,-1,1},{1,1,1},{1,1,-1}},
|
||||
{{1,-1,1},{-1,-1,1},{-1,1,1},{1,1,1}},{{-1,-1,1},{-1,-1,-1},{-1,1,-1},{-1,1,1}},
|
||||
{{-1,1,-1},{1,1,-1},{1,1,1},{-1,1,1}},{{-1,-1,1},{1,-1,1},{1,-1,-1},{-1,-1,-1}}};
|
||||
float nm[6][3]={{0,0,-1},{1,0,0},{0,0,1},{-1,0,0},{0,1,0},{0,-1,0}};
|
||||
for(int fi=0;fi<6;fi++) for(int vi=0;vi<4;vi++){
|
||||
int i=fi*4+vi;
|
||||
v[i].p[0]=f[fi][vi][0]*s+cx; v[i].p[1]=f[fi][vi][1]*s+cy; v[i].p[2]=f[fi][vi][2]*s+cz;
|
||||
v[i].n[0]=nm[fi][0]; v[i].n[1]=nm[fi][1]; v[i].n[2]=nm[fi][2];
|
||||
v[i].c[0]=cr; v[i].c[1]=cg; v[i].c[2]=cb; v[i].c[3]=1;
|
||||
}
|
||||
uint32_t idx[36]; for(int fi=0;fi<6;fi++){int b=fi*4;idx[fi*6]=b;idx[fi*6+1]=b+1;idx[fi*6+2]=b+2;idx[fi*6+3]=b;idx[fi*6+4]=b+2;idx[fi*6+5]=b+3;}
|
||||
ID3D11Buffer *vb,*ib;D3D11_BUFFER_DESC bd={};D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*24;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;sd.pSysMem=v;
|
||||
dev->lpVtbl->CreateBuffer(dev,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*36;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;sd.pSysMem=idx;
|
||||
dev->lpVtbl->CreateBuffer(dev,&bd,&sd,&ib);
|
||||
UINT s2=sizeof(V),o=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,36,0,0);
|
||||
ib->lpVtbl->Release(ib);vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if(!g_dev) return;
|
||||
ID3D11DeviceContext* ctx=g_dev->context;
|
||||
g_time+=0.016f;
|
||||
|
||||
float sw=(float)g_dev->width,sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f),asp=sw/sh;
|
||||
float mvp[16]={0}; mvp[0]=fov/asp;mvp[5]=-fov;mvp[10]=1;mvp[11]=-1;mvp[14]=0.1f;mvp[15]=1;
|
||||
Mat4 pm,pt;memcpy(&pm,mvp,sizeof(Mat4));mat4_transpose(&pm,&pt);
|
||||
|
||||
graphics_device_clear(g_dev,0.15f,0.18f,0.25f,1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState*rs=NULL;g_dev->device->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState*dss=NULL;g_dev->device->lpVtbl->CreateDepthStencilState(g_dev,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
// 绑定光照 shader
|
||||
ctx->lpVtbl->VSSetShader(ctx,g_vs,NULL,0);
|
||||
ctx->lpVtbl->PSSetShader(ctx,g_ps,NULL,0);
|
||||
ctx->lpVtbl->IASetInputLayout(ctx,g_il);
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx,0,1,&g_cb);
|
||||
ctx->lpVtbl->UpdateSubresource(ctx,(ID3D11Resource*)g_cb,0,NULL,&pt,0,0);
|
||||
|
||||
// 更新光照 CB
|
||||
float light_data[16]={0};
|
||||
light_data[0]=g_sun->direction[0];light_data[1]=g_sun->direction[1];light_data[2]=g_sun->direction[2];
|
||||
light_data[4]=g_sun->color[0];light_data[5]=g_sun->color[1];light_data[6]=g_sun->color[2];
|
||||
light_data[7]=g_sun->intensity;
|
||||
light_data[8]=0.15f;light_data[9]=0.15f;light_data[10]=0.2f;
|
||||
ctx->lpVtbl->VSSetConstantBuffers(ctx,1,1,&g_cb);
|
||||
|
||||
draw_lit_cube(ctx,g_dev, 0,0,0.5f, 0.3f, 1,0.3f,0.3f);
|
||||
draw_lit_cube(ctx,g_dev,-0.8f,0,0.7f, 0.2f, 0.3f,1,0.3f);
|
||||
draw_lit_cube(ctx,g_dev, 0.8f,0.3f,0.3f, 0.15f, 0.3f,0.3f,1);
|
||||
draw_lit_cube(ctx,g_dev, 0,-0.2f,0.8f, 0.4f, 0.8f,0.8f,0.2f);
|
||||
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine*e,int k){if(k==VK_ESCAPE)engine_request_quit(e);}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int){
|
||||
EngineConfig cfg=engine_default_config();cfg.app_name="lity3d Light Test";
|
||||
Engine*e=engine_create();if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
InitShaders();
|
||||
g_sun=light_create_dir(1.0f,0.95f,0.8f,1.2f, -0.5f,-1.0f,-0.3f);
|
||||
engine_set_render_callback(e,on_render);engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
light_destroy(g_sun);graphics_device_destroy(g_dev);engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
// ============================================================================
|
||||
// ly_interpreter.c - .ly 积木语言独立解释器
|
||||
// 直接解析 .ly 格式,不依赖引擎 VisualScript 框架
|
||||
// 用法: ly_interpreter.exe <script.ly>
|
||||
// ============================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
// === 数据结构 ===
|
||||
typedef union { double num; char str[256]; int bool_val; } Value;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
char name[64];
|
||||
float x, y;
|
||||
char data[256];
|
||||
int color;
|
||||
Value inputs[8];
|
||||
int input_count;
|
||||
Value outputs[4];
|
||||
int output_count;
|
||||
} Block;
|
||||
|
||||
typedef struct {
|
||||
int from_block, from_slot;
|
||||
int to_block, to_slot;
|
||||
} Wire;
|
||||
|
||||
#define MAX_BLOCKS 256
|
||||
#define MAX_WIRES 256
|
||||
|
||||
static Block g_blocks[MAX_BLOCKS];
|
||||
static int g_block_count = 0;
|
||||
static Wire g_wires[MAX_WIRES];
|
||||
static int g_wire_count = 0;
|
||||
|
||||
// === 解析 ===
|
||||
|
||||
static void trim(char* s) {
|
||||
char* p = s;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (p != s) memmove(s, p, strlen(p) + 1);
|
||||
int len = strlen(s);
|
||||
while (len > 0 && (s[len-1] == '\n' || s[len-1] == '\r' || s[len-1] == ' ')) s[--len] = 0;
|
||||
}
|
||||
|
||||
static int parse_ly(const char* path) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) { fprintf(stderr, "Cannot open %s\n", path); return 0; }
|
||||
|
||||
char line[1024];
|
||||
int section = 0; // 0=none, 1=block, 2=wire
|
||||
int cur_bid = -1;
|
||||
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
trim(line);
|
||||
if (line[0] == '#' || line[0] == 0) continue;
|
||||
|
||||
if (strcmp(line, "[B]") == 0 || strcmp(line, "[Block]") == 0) { section = 1; cur_bid = -1; continue; }
|
||||
if (strcmp(line, "[W]") == 0 || strcmp(line, "[Wire]") == 0) { section = 2; continue; }
|
||||
if (line[0] == '[') { section = 0; continue; }
|
||||
|
||||
if (section == 1) {
|
||||
char* eq = strchr(line, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0; char* key = line; char* val = eq + 1;
|
||||
|
||||
if (strcmp(key, "id") == 0) {
|
||||
cur_bid = g_block_count;
|
||||
memset(&g_blocks[cur_bid], 0, sizeof(Block));
|
||||
g_blocks[cur_bid].id = atoi(val);
|
||||
g_block_count++;
|
||||
} else if (cur_bid >= 0) {
|
||||
if (strcmp(key, "name") == 0) strncpy(g_blocks[cur_bid].name, val, 63);
|
||||
else if (strcmp(key, "p") == 0 || strcmp(key, "pos") == 0) sscanf(val, "%f,%f", &g_blocks[cur_bid].x, &g_blocks[cur_bid].y);
|
||||
else if (strcmp(key, "d") == 0 || strcmp(key, "data") == 0) strncpy(g_blocks[cur_bid].data, val, 255);
|
||||
else if (strcmp(key, "c") == 0 || strcmp(key, "color") == 0) g_blocks[cur_bid].color = atoi(val);
|
||||
}
|
||||
} else if (section == 2) {
|
||||
Wire* w = &g_wires[g_wire_count];
|
||||
char* eq = strchr(line, '=');
|
||||
if (!eq) continue;
|
||||
*eq = 0; char* key = line; char* val = eq + 1;
|
||||
|
||||
if (strcmp(key, "a") == 0 || strcmp(key, "from") == 0) {
|
||||
w->from_block = atoi(val) / 10000;
|
||||
w->from_slot = atoi(val) % 10000;
|
||||
} else if (strcmp(key, "b") == 0 || strcmp(key, "to") == 0) {
|
||||
w->to_block = atoi(val) / 10000;
|
||||
w->to_slot = atoi(val) % 10000;
|
||||
if (w->from_block > 0) g_wire_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
printf("Parsed: %d blocks, %d wires\n", g_block_count, g_wire_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// === 查找 ===
|
||||
|
||||
static Block* find_block(int id) {
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
if (g_blocks[i].id == id) return &g_blocks[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 找到从某个 block 的 output_slot 出发,连接到的下一个 block
|
||||
static Block* follow_wire(int from_id, int from_slot) {
|
||||
for (int i = 0; i < g_wire_count; i++) {
|
||||
if (g_wires[i].from_block == from_id && g_wires[i].from_slot == from_slot)
|
||||
return find_block(g_wires[i].to_block);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 获取连接到某个 block input_slot 的值
|
||||
static Value get_input_value(int block_id, int slot) {
|
||||
for (int i = 0; i < g_wire_count; i++) {
|
||||
if (g_wires[i].to_block == block_id && g_wires[i].to_slot == slot) {
|
||||
Block* src = find_block(g_wires[i].from_block);
|
||||
if (src && src->output_count > g_wires[i].from_slot)
|
||||
return src->outputs[g_wires[i].from_slot];
|
||||
}
|
||||
}
|
||||
Value v; v.num = 0; return v;
|
||||
}
|
||||
|
||||
// === 解释执行 ===
|
||||
|
||||
static int g_variables[64]; // 简单变量存储
|
||||
static char g_var_names[64][64];
|
||||
static int g_var_count = 0;
|
||||
|
||||
static int get_var(const char* name) {
|
||||
for (int i = 0; i < g_var_count; i++)
|
||||
if (strcmp(g_var_names[i], name) == 0) return g_variables[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_var(const char* name, int val) {
|
||||
for (int i = 0; i < g_var_count; i++)
|
||||
if (strcmp(g_var_names[i], name) == 0) { g_variables[i] = val; return; }
|
||||
if (g_var_count < 64) { strncpy(g_var_names[g_var_count], name, 63); g_variables[g_var_count++] = val; }
|
||||
}
|
||||
|
||||
static void execute(Block* block, int depth);
|
||||
|
||||
static void execute_block(Block* b, int depth) {
|
||||
if (!b) return;
|
||||
if (depth > 100) { printf("Stack overflow!\n"); return; }
|
||||
|
||||
const char* n = b->name;
|
||||
|
||||
if (strcmp(n, "开始") == 0) {
|
||||
// Follow output wire
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "移动物体") == 0) {
|
||||
Value dx = get_input_value(b->id, 1);
|
||||
Value dy = get_input_value(b->id, 2);
|
||||
Value dz = get_input_value(b->id, 3);
|
||||
printf(" [move] dx=%.1f dy=%.1f dz=%.1f\n", dx.num, dy.num, dz.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "旋转物体") == 0) {
|
||||
Value dx = get_input_value(b->id, 1);
|
||||
Value dy = get_input_value(b->id, 2);
|
||||
Value dz = get_input_value(b->id, 3);
|
||||
printf(" [rotate] rx=%.1f ry=%.1f rz=%.1f\n", dx.num, dy.num, dz.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "当按键") == 0) {
|
||||
// Event: just follow output (simulated - always fires)
|
||||
printf(" [key event] key='%s'\n", b->data);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "当点击") == 0) {
|
||||
printf(" [click event]\n");
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "打印") == 0 || strcmp(n, "print") == 0) {
|
||||
Value msg = get_input_value(b->id, 1);
|
||||
printf(" [print] %s\n", msg.str[0] ? msg.str : b->data);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "等待") == 0 || strcmp(n, "wait") == 0) {
|
||||
Value secs = get_input_value(b->id, 1);
|
||||
double s = secs.num > 0 ? secs.num : atof(b->data);
|
||||
printf(" [wait] %.1fs\n", s);
|
||||
// In real engine, this would pause. For now, just continue.
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "循环") == 0 || strcmp(n, "loop") == 0) {
|
||||
Value count = get_input_value(b->id, 1);
|
||||
int n = count.num > 0 ? (int)count.num : atoi(b->data);
|
||||
if (n <= 0) n = 1;
|
||||
printf(" [loop] %d times\n", n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Block* body = follow_wire(b->id, 0);
|
||||
execute(body, depth + 1);
|
||||
}
|
||||
}
|
||||
else if (strcmp(n, "如果") == 0 || strcmp(n, "if") == 0) {
|
||||
Value cond = get_input_value(b->id, 1);
|
||||
printf(" [if] condition=%d\n", cond.bool_val);
|
||||
Block* next = follow_wire(b->id, cond.bool_val ? 0 : 1);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "数学运算") == 0 || strcmp(n, "+") == 0) {
|
||||
Value a = get_input_value(b->id, 0);
|
||||
Value b2 = get_input_value(b->id, 1);
|
||||
b->outputs[0].num = a.num + b2.num;
|
||||
printf(" [add] %.1f + %.1f = %.1f\n", a.num, b2.num, b->outputs[0].num);
|
||||
}
|
||||
else if (strcmp(n, "变量设置") == 0 || strcmp(n, "set_var") == 0) {
|
||||
Value v = get_input_value(b->id, 1);
|
||||
set_var(b->data, (int)v.num);
|
||||
printf(" [set_var] %s = %d\n", b->data, (int)v.num);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
else if (strcmp(n, "变量读取") == 0 || strcmp(n, "get_var") == 0) {
|
||||
int v = get_var(b->data);
|
||||
b->outputs[0].num = v;
|
||||
printf(" [get_var] %s = %d\n", b->data, v);
|
||||
}
|
||||
else {
|
||||
printf(" [unknown] '%s'\n", n);
|
||||
Block* next = follow_wire(b->id, 0);
|
||||
execute(next, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void execute(Block* block, int depth) {
|
||||
if (!block) return;
|
||||
execute_block(block, depth);
|
||||
}
|
||||
|
||||
// === 主函数 ===
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const char* script = "Demo/test.ly";
|
||||
if (argc > 1) script = argv[1];
|
||||
|
||||
printf("=== lity3d .ly Interpreter ===\n");
|
||||
printf("Script: %s\n\n", script);
|
||||
|
||||
if (!parse_ly(script)) return 1;
|
||||
|
||||
printf("\n--- Blocks ---\n");
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
printf(" [%d] %s data='%s' pos=(%.0f,%.0f)\n", g_blocks[i].id, g_blocks[i].name, g_blocks[i].data, g_blocks[i].x, g_blocks[i].y);
|
||||
|
||||
printf("\n--- Wires ---\n");
|
||||
for (int i = 0; i < g_wire_count; i++)
|
||||
printf(" [%d].out%d -> [%d].in%d\n", g_wires[i].from_block, g_wires[i].from_slot, g_wires[i].to_block, g_wires[i].to_slot);
|
||||
|
||||
printf("\n--- Execute ---\n");
|
||||
|
||||
// Find start block
|
||||
Block* start = NULL;
|
||||
for (int i = 0; i < g_block_count; i++)
|
||||
if (strcmp(g_blocks[i].name, "开始") == 0) { start = &g_blocks[i]; break; }
|
||||
|
||||
if (!start) {
|
||||
// Try to find any block with incoming wires as entry point
|
||||
// Or just execute the first block
|
||||
if (g_block_count > 0) start = &g_blocks[0];
|
||||
}
|
||||
|
||||
if (start) {
|
||||
execute(start, 0);
|
||||
} else {
|
||||
printf("No executable blocks found.\n");
|
||||
}
|
||||
|
||||
printf("\n--- Done ---\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// mesh_debug.c - 精确定位 mesh 系统 bug
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static ID3D11Buffer* g_vb = NULL;
|
||||
static ID3D11Buffer* g_ib = NULL;
|
||||
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
float sw=(float)g_dev->width, sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f), asp=sw/sh;
|
||||
|
||||
float mvp[16];
|
||||
mvp[0]=fov/asp; mvp[5]=-fov; mvp[10]=1; mvp[11]=-1; mvp[14]=0.1f; mvp[15]=1;
|
||||
Mat4 pm, pt; memcpy(&pm, mvp, sizeof(Mat4)); mat4_transpose(&pm, &pt);
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
D3D11_VIEWPORT vp={}; vp.Width=sw; vp.Height=sh; vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={}; rd.FillMode=D3D11_FILL_SOLID; rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs=NULL; g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={}; dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState* dss=NULL; g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&pt);
|
||||
|
||||
// 用 init 时创建的 VB 画
|
||||
UINT stride=sizeof(V), offset=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&g_vb,&stride,&offset);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,g_ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
|
||||
if(rs) rs->lpVtbl->Release(rs);
|
||||
if(dss) dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if(key==VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) {
|
||||
EngineConfig cfg=engine_default_config(); cfg.app_name="mesh debug";
|
||||
Engine* e=engine_create(); if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
g_shader=shader_create(); shader_compile(g_shader,g_dev->device,NULL,NULL,0,0);
|
||||
|
||||
// WinMain 中创建 VB/IB(跟 mesh_create_cube 一样的时机)
|
||||
V v[4]={{{-0.5f,-0.5f,0.5f},{0,0,1},{0,0},{1,0,0,1}},{{0.5f,-0.5f,0.5f},{0,0,1},{1,0},{0,1,0,1}},{{0.5f,0.5f,0.5f},{0,0,1},{1,1},{0,0,1,1}},{{-0.5f,0.5f,0.5f},{0,0,1},{0,1},{1,1,1,1}}};
|
||||
uint32_t idx[6]={0,1,2,0,2,3};
|
||||
D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&g_vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&g_ib);
|
||||
|
||||
engine_set_render_callback(e,on_render); engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
if(g_vb)g_vb->lpVtbl->Release(g_vb); if(g_ib)g_ib->lpVtbl->Release(g_ib);
|
||||
shader_destroy(g_shader); graphics_device_destroy(g_dev); engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static ID3D11Device* g_dev; static ID3D11DeviceContext* g_ctx;
|
||||
static IDXGISwapChain* g_sc; static ID3D11RenderTargetView* g_rtv;
|
||||
static ID3D11VertexShader* g_vs; static ID3D11PixelShader* g_ps;
|
||||
static ID3D11InputLayout* g_il; static ID3D11Buffer* g_cb;
|
||||
|
||||
static float cam_dist = 5.0f, cam_yaw = 0.5f, cam_pitch = 0.3f;
|
||||
static int drag = 0, last_mx, last_my;
|
||||
static int key_w=0,key_s=0,key_a=0,key_d=0,key_q=0,key_e=0;
|
||||
|
||||
typedef struct { float p[3], n[3], u[2], c[4]; } V3D;
|
||||
|
||||
static V3D* obj_verts = NULL;
|
||||
static uint32_t* obj_idx = NULL;
|
||||
static int obj_vcount = 0, obj_icount = 0;
|
||||
static ID3D11Buffer* obj_vb = NULL;
|
||||
static ID3D11Buffer* obj_ib = NULL;
|
||||
|
||||
static int LoadOBJ(const char* path) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return -1;
|
||||
int max_v = 16384, max_f = 32768;
|
||||
float* vpos = (float*)malloc(max_v * 3 * sizeof(float));
|
||||
int vc = 0;
|
||||
int* fidx = (int*)malloc(max_f * 3 * sizeof(int));
|
||||
int fc = 0;
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (line[0] == 'v' && line[1] == ' ') {
|
||||
float x, y, z;
|
||||
if (sscanf(line + 2, "%f %f %f", &x, &y, &z) == 3 && vc < max_v) {
|
||||
vpos[vc*3]=x; vpos[vc*3+1]=y; vpos[vc*3+2]=z; vc++;
|
||||
}
|
||||
} else if (line[0] == 'f' && line[1] == ' ') {
|
||||
int v0, v1, v2;
|
||||
char* p = line + 2;
|
||||
v0 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v1 = atoi(p) - 1; while (*p && *p != ' ') p++; p++;
|
||||
v2 = atoi(p) - 1;
|
||||
if (v0 >= 0 && v1 >= 0 && v2 >= 0 && fc < max_f) {
|
||||
fidx[fc*3]=v0; fidx[fc*3+1]=v1; fidx[fc*3+2]=v2; fc++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (vc == 0 || fc == 0) { free(vpos); free(fidx); return -1; }
|
||||
|
||||
obj_vcount = fc * 3;
|
||||
obj_icount = fc * 3;
|
||||
obj_verts = (V3D*)calloc(obj_vcount, sizeof(V3D));
|
||||
obj_idx = (uint32_t*)malloc(obj_icount * sizeof(uint32_t));
|
||||
|
||||
for (int i = 0; i < fc; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int vi = fidx[i*3+j];
|
||||
int oi = i*3+j;
|
||||
if (vi < vc) {
|
||||
obj_verts[oi].p[0] = vpos[vi*3];
|
||||
obj_verts[oi].p[1] = vpos[vi*3+1];
|
||||
obj_verts[oi].p[2] = vpos[vi*3+2];
|
||||
}
|
||||
obj_verts[oi].c[0] = 0.6f; obj_verts[oi].c[1] = 0.7f; obj_verts[oi].c[2] = 0.8f; obj_verts[oi].c[3] = 1;
|
||||
obj_idx[oi] = oi;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < fc; i++) {
|
||||
float* p0 = obj_verts[i*3].p;
|
||||
float* p1 = obj_verts[i*3+1].p;
|
||||
float* p2 = obj_verts[i*3+2].p;
|
||||
float e1[3]={p1[0]-p0[0],p1[1]-p0[1],p1[2]-p0[2]};
|
||||
float e2[3]={p2[0]-p0[0],p2[1]-p0[1],p2[2]-p0[2]};
|
||||
float nx=e1[1]*e2[2]-e1[2]*e2[1], ny=e1[2]*e2[0]-e1[0]*e2[2], nz=e1[0]*e2[1]-e1[1]*e2[0];
|
||||
float nl=sqrtf(nx*nx+ny*ny+nz*nz);
|
||||
if(nl>0.0001f){nx/=nl;ny/=nl;nz/=nl;}
|
||||
for(int j=0;j<3;j++){obj_verts[i*3+j].n[0]=nx;obj_verts[i*3+j].n[1]=ny;obj_verts[i*3+j].n[2]=nz;}
|
||||
}
|
||||
|
||||
D3D11_BUFFER_DESC bd; D3D11_SUBRESOURCE_DATA sd;
|
||||
memset(&bd,0,sizeof(bd));memset(&sd,0,sizeof(sd));
|
||||
bd.ByteWidth=sizeof(V3D)*obj_vcount;bd.Usage=D3D11_USAGE_DEFAULT;bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=obj_verts;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&obj_vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*obj_icount;bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=obj_idx;g_dev->lpVtbl->CreateBuffer(g_dev,&bd,&sd,&obj_ib);
|
||||
|
||||
free(vpos); free(fidx); free(obj_verts); free(obj_idx);
|
||||
obj_verts = NULL; obj_idx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Init(HWND h) {
|
||||
HRESULT hr;
|
||||
DXGI_SWAP_CHAIN_DESC sd;memset(&sd,0,sizeof(sd));sd.BufferCount=2;sd.BufferDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;sd.BufferDesc.RefreshRate.Numerator=60;sd.BufferUsage=DXGI_USAGE_RENDER_TARGET_OUTPUT;sd.OutputWindow=h;sd.SampleDesc.Count=1;sd.Windowed=TRUE;sd.SwapEffect=DXGI_SWAP_EFFECT_DISCARD;
|
||||
D3D_FEATURE_LEVEL fl=D3D_FEATURE_LEVEL_11_0,gt;hr=D3D11CreateDeviceAndSwapChain(NULL,D3D_DRIVER_TYPE_HARDWARE,NULL,0,&fl,1,D3D11_SDK_VERSION,&sd,&g_sc,&g_dev,>,&g_ctx);if(FAILED(hr))return;
|
||||
ID3D11Texture2D*bb=NULL;hr=g_sc->lpVtbl->GetBuffer(g_sc,0,&IID_ID3D11Texture2D,(void**)&bb);if(FAILED(hr)||!bb)return;hr=g_dev->lpVtbl->CreateRenderTargetView(g_dev,(ID3D11Resource*)bb,NULL,&g_rtv);bb->lpVtbl->Release(bb);if(FAILED(hr))return;
|
||||
const char*vs="cbuffer CB:register(b0){float4x4 WVP;};struct I{float3 p:POSITION;float3 n:NORMAL;float2 u:TEXCOORD;float4 c:COLOR;};struct O{float4 p:SV_POSITION;float3 n:NORMAL;float4 c:COLOR;};O main(I i){O o;o.p=mul(float4(i.p,1),WVP);o.n=i.n;o.c=i.c;return o;}";
|
||||
const char*ps="struct I{float3 n:NORMAL;float4 c:COLOR;};float4 main(float4 p:SV_POSITION,I i):SV_Target{float l=normalize(float3(0.3,1,0.5));float d=max(dot(normalize(i.n),l),0.2);return float4(i.c.rgb*d,1);}";
|
||||
ID3DBlob*b1,*b2,*e;D3DCompile(vs,(UINT)strlen(vs),NULL,NULL,NULL,"main","vs_5_0",0,0,&b1,&e);if(e){e->lpVtbl->Release(e);e=NULL;}D3DCompile(ps,(UINT)strlen(ps),NULL,NULL,NULL,"main","ps_5_0",0,0,&b2,&e);if(e){e->lpVtbl->Release(e);e=NULL;}if(!b1||!b2)return;
|
||||
g_dev->lpVtbl->CreateVertexShader(g_dev,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),NULL,&g_vs);g_dev->lpVtbl->CreatePixelShader(g_dev,b2->lpVtbl->GetBufferPointer(b2),b2->lpVtbl->GetBufferSize(b2),NULL,&g_ps);
|
||||
D3D11_INPUT_ELEMENT_DESC el[4];memset(el,0,sizeof(el));el[0].SemanticName="POSITION";el[0].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[0].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[1].SemanticName="NORMAL";el[1].AlignedByteOffset=12;el[1].Format=DXGI_FORMAT_R32G32B32_FLOAT;el[1].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[2].SemanticName="TEXCOORD";el[2].AlignedByteOffset=24;el[2].Format=DXGI_FORMAT_R32G32_FLOAT;el[2].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;el[3].SemanticName="COLOR";el[3].AlignedByteOffset=32;el[3].Format=DXGI_FORMAT_R32G32B32A32_FLOAT;el[3].InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
|
||||
g_dev->lpVtbl->CreateInputLayout(g_dev,el,4,b1->lpVtbl->GetBufferPointer(b1),b1->lpVtbl->GetBufferSize(b1),&g_il);b1->lpVtbl->Release(b1);b2->lpVtbl->Release(b2);
|
||||
D3D11_BUFFER_DESC cbd;memset(&cbd,0,sizeof(cbd));cbd.ByteWidth=256;cbd.Usage=D3D11_USAGE_DEFAULT;cbd.BindFlags=D3D11_BIND_CONSTANT_BUFFER;g_dev->lpVtbl->CreateBuffer(g_dev,&cbd,NULL,&g_cb);
|
||||
}
|
||||
|
||||
static void mat4_perspective(float* m, float fov, float asp, float zn, float zf) {
|
||||
memset(m, 0, 64);
|
||||
float f = 1.0f / tanf(fov / 2);
|
||||
m[0] = f / asp; m[5] = -f;
|
||||
m[10] = zf / (zf - zn); m[11] = -zn * zf / (zf - zn);
|
||||
m[14] = 1; m[15] = 0;
|
||||
}
|
||||
|
||||
static void mat4_lookat(float* m, float ex, float ey, float ez, float tx, float ty, float tz) {
|
||||
float fx=tx-ex, fy=ty-ey, fz=tz-ez;
|
||||
float fl=sqrtf(fx*fx+fy*fy+fz*fz);fx/=fl;fy/=fl;fz/=fl;
|
||||
float rx=fy*0-fz*1,ry=fz*0-fx*0,rz=fx*1-fy*0;
|
||||
float rl=sqrtf(rx*rx+ry*ry+rz*rz);rx/=rl;ry/=rl;rz/=rl;
|
||||
float ux=ry*fz-rz*fy,uy=rz*fx-rx*fz,uz=rx*fy-ry*fx;
|
||||
memset(m, 0, 64);
|
||||
m[0]=rx*1;m[1]=ux*1;m[2]=fx*1;
|
||||
m[4]=ry*1;m[5]=uy*1;m[6]=fy*1;
|
||||
m[8]=rz*1;m[9]=uz*1;m[10]=fz*1;
|
||||
m[12]=-(rx*ex+ry*ey+rz*ez);m[13]=-(ux*ex+uy*ey+uz*ez);m[14]=-(fx*ex+fy*ey+fz*ez);m[15]=1;
|
||||
}
|
||||
|
||||
static void mat4_mul(float* o, float* a, float* b) {
|
||||
float t[16];for(int i=0;i<4;i++)for(int j=0;j<4;j++){t[i*4+j]=0;for(int k=0;k<4;k++)t[i*4+j]+=a[i*4+k]*b[k*4+j];}
|
||||
memcpy(o,t,64);
|
||||
}
|
||||
|
||||
static void Frame(void) {
|
||||
float dt = 0.016f, rspd = 2.0f * dt, mspeed = 3.0f * dt;
|
||||
if (key_a) cam_yaw -= rspd; if (key_d) cam_yaw += rspd;
|
||||
if (key_q) cam_pitch -= rspd; if (key_e) cam_pitch += rspd;
|
||||
if (key_w) cam_dist -= mspeed; if (key_s) cam_dist += mspeed;
|
||||
if (cam_dist < 1.0f) cam_dist = 1.0f; if (cam_dist > 20.0f) cam_dist = 20.0f;
|
||||
if (cam_pitch > 1.5f) cam_pitch = 1.5f; if (cam_pitch < -1.5f) cam_pitch = -1.5f;
|
||||
|
||||
float ex = cam_dist * sinf(cam_yaw) * cosf(cam_pitch);
|
||||
float ey = cam_dist * sinf(cam_pitch);
|
||||
float ez = cam_dist * cosf(cam_yaw) * cosf(cam_pitch);
|
||||
|
||||
float view[16], proj[16], vp[16], tmp[16];
|
||||
mat4_lookat(view, ex, ey, ez, 0, 0, 0);
|
||||
mat4_perspective(proj, 0.8f, 1280.0f/720.0f, 0.1f, 100.0f);
|
||||
mat4_mul(tmp, view, proj);
|
||||
float vp_t[16]; for(int i=0;i<4;i++)for(int j=0;j<4;j++) vp_t[i*4+j]=tmp[j*4+i];
|
||||
|
||||
float cl[4]={.15f,.18f,.22f,1};
|
||||
g_ctx->lpVtbl->OMSetRenderTargets(g_ctx,1,&g_rtv,NULL);g_ctx->lpVtbl->ClearRenderTargetView(g_ctx,g_rtv,cl);
|
||||
D3D11_VIEWPORT vp2;memset(&vp2,0,sizeof(vp2));vp2.Width=1280;vp2.Height=720;vp2.MaxDepth=1;g_ctx->lpVtbl->RSSetViewports(g_ctx,1,&vp2);
|
||||
D3D11_RASTERIZER_DESC rd;memset(&rd,0,sizeof(rd));rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;ID3D11RasterizerState*rs;g_dev->lpVtbl->CreateRasterizerState(g_dev,&rd,&rs);g_ctx->lpVtbl->RSSetState(g_ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC ds;memset(&ds,0,sizeof(ds));ds.DepthEnable=FALSE;ID3D11DepthStencilState*dss;g_dev->lpVtbl->CreateDepthStencilState(g_dev,&ds,&dss);g_ctx->lpVtbl->OMSetDepthStencilState(g_ctx,dss,0);
|
||||
g_ctx->lpVtbl->IASetPrimitiveTopology(g_ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);g_ctx->lpVtbl->VSSetShader(g_ctx,g_vs,NULL,0);g_ctx->lpVtbl->PSSetShader(g_ctx,g_ps,NULL,0);g_ctx->lpVtbl->IASetInputLayout(g_ctx,g_il);g_ctx->lpVtbl->VSSetConstantBuffers(g_ctx,0,1,&g_cb);g_ctx->lpVtbl->UpdateSubresource(g_ctx,(ID3D11Resource*)g_cb,0,NULL,vp_t,0,0);
|
||||
|
||||
if (obj_vb && obj_ib) {
|
||||
UINT stride = sizeof(V3D), off = 0;
|
||||
g_ctx->lpVtbl->IASetVertexBuffers(g_ctx, 0, 1, &obj_vb, &stride, &off);
|
||||
g_ctx->lpVtbl->IASetIndexBuffer(g_ctx, obj_ib, DXGI_FORMAT_R32_UINT, 0);
|
||||
g_ctx->lpVtbl->DrawIndexed(g_ctx, obj_icount, 0, 0);
|
||||
}
|
||||
|
||||
if(rs)rs->lpVtbl->Release(rs);if(dss)dss->lpVtbl->Release(dss);
|
||||
g_sc->lpVtbl->Present(g_sc, 1, 0);
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK WP(HWND h,UINT m,WPARAM w,LPARAM l){
|
||||
switch(m){
|
||||
case WM_LBUTTONDOWN:drag=1;last_mx=(short)LOWORD(l);last_my=(short)HIWORD(l);SetCapture(h);break;
|
||||
case WM_LBUTTONUP:drag=0;ReleaseCapture();break;
|
||||
case WM_MOUSEMOVE:if(drag){int mx=(short)LOWORD(l),my=(short)HIWORD(l);cam_yaw+=(mx-last_mx)*0.005f;cam_pitch+=(my-last_my)*0.005f;if(cam_pitch>1.5f)cam_pitch=1.5f;if(cam_pitch<-1.5f)cam_pitch=-1.5f;last_mx=mx;last_my=my;}break;
|
||||
case WM_MOUSEWHEEL:cam_dist-=(short)HIWORD(w)/120.0f;if(cam_dist<1)cam_dist=1;if(cam_dist>20)cam_dist=20;break;
|
||||
case WM_KEYDOWN:switch(w){case 'A':key_a=1;break;case 'D':key_d=1;break;case 'W':key_w=1;break;case 'S':key_s=1;break;case 'Q':key_q=1;break;case 'E':key_e=1;break;case VK_ESCAPE:PostQuitMessage(0);break;}break;
|
||||
case WM_KEYUP:switch(w){case 'A':key_a=0;break;case 'D':key_d=0;break;case 'W':key_w=0;break;case 'S':key_s=0;break;case 'Q':key_q=0;break;case 'E':key_e=0;break;}break;
|
||||
case WM_DESTROY:PostQuitMessage(0);return 0;
|
||||
}return DefWindowProcW(h,m,w,l);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR nC,int nS){
|
||||
(void)nS;
|
||||
WNDCLASSEXW wc;memset(&wc,0,sizeof(wc));wc.cbSize=sizeof(wc);wc.style=CS_CLASSDC;wc.lpfnWndProc=WP;wc.hInstance=hI;wc.lpszClassName=L"obj_viewer";
|
||||
RegisterClassExW(&wc);
|
||||
HWND hwnd=CreateWindowW(L"obj_viewer",L"OBJ Viewer - Mouse drag orbit, WASD move, Scroll zoom",WS_OVERLAPPEDWINDOW,100,100,1280,720,NULL,NULL,hI,NULL);
|
||||
if(!hwnd)return -1;ShowWindow(hwnd,SW_SHOW);UpdateWindow(hwnd);Init(hwnd);
|
||||
|
||||
char path[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, path, MAX_PATH);
|
||||
char* sl = strrchr(path, '\\');
|
||||
if (sl) { *(sl+1) = '\0'; strcat(path, "Assets\\cube.obj"); }
|
||||
else strcpy(path, "Assets\\cube.obj");
|
||||
LoadOBJ(path);
|
||||
|
||||
MSG msg;
|
||||
while(1){while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);if(msg.message==WM_QUIT)goto done;}Frame();}
|
||||
done:
|
||||
if(obj_vb)obj_vb->lpVtbl->Release(obj_vb);if(obj_ib)obj_ib->lpVtbl->Release(obj_ib);
|
||||
if(g_cb)g_cb->lpVtbl->Release(g_cb);if(g_il)g_il->lpVtbl->Release(g_il);if(g_vs)g_vs->lpVtbl->Release(g_vs);if(g_ps)g_ps->lpVtbl->Release(g_ps);if(g_rtv)g_rtv->lpVtbl->Release(g_rtv);if(g_sc)g_sc->lpVtbl->Release(g_sc);if(g_ctx)g_ctx->lpVtbl->Release(g_ctx);if(g_dev)g_dev->lpVtbl->Release(g_dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
#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/camera.h"
|
||||
#include "../Engine/Rendering/camera_controller.h"
|
||||
#include "../Engine/Terrain/terrain.h"
|
||||
#include "../Engine/Terrain/terrain_manager.h"
|
||||
#include "../Engine/Rendering/frustum.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/Scene/scene_render.h"
|
||||
#include "../Engine/Scene/scene_serialize.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <Windows.h>
|
||||
|
||||
static AssetManager* g_assets = NULL;
|
||||
static Asset* g_shader_asset = NULL;
|
||||
static Camera g_camera;
|
||||
static CameraController g_controller;
|
||||
static TerrainManager* g_terrain = NULL;
|
||||
static Material* g_terrain_mat = NULL;
|
||||
static Mesh* g_cube = NULL;
|
||||
static Material* g_cube_mat = NULL;
|
||||
static Mesh* g_water = NULL;
|
||||
static Material* g_water_mat = NULL;
|
||||
static Scene* g_test_scene = NULL;
|
||||
|
||||
static int g_mouse_down[3] = {0};
|
||||
static int g_last_mouse_x = 0, g_last_mouse_y = 0;
|
||||
static int g_mouse_first = 1;
|
||||
static int g_walk_mode = 0;
|
||||
|
||||
// ============================================================================
|
||||
// 简易植被/岩石散布
|
||||
// ============================================================================
|
||||
#define MAX_SCATTER 512
|
||||
|
||||
typedef struct {
|
||||
Mesh* mesh;
|
||||
Material* mat;
|
||||
Mat4 world;
|
||||
} ScatterInstance;
|
||||
|
||||
static ScatterInstance g_scatter[MAX_SCATTER];
|
||||
static int g_scatter_count = 0;
|
||||
|
||||
static void add_scatter(Mesh* mesh, Material* mat, Vec3 pos, Vec3 scale) {
|
||||
if (g_scatter_count >= MAX_SCATTER) return;
|
||||
ScatterInstance* s = &g_scatter[g_scatter_count++];
|
||||
s->mesh = mesh;
|
||||
s->mat = mat;
|
||||
mat4_identity(&s->world);
|
||||
s->world.m[0][0] = scale.x;
|
||||
s->world.m[1][1] = scale.y;
|
||||
s->world.m[2][2] = scale.z;
|
||||
s->world.m[3][0] = pos.x;
|
||||
s->world.m[3][1] = pos.y;
|
||||
s->world.m[3][2] = pos.z;
|
||||
}
|
||||
|
||||
static void generate_scatter(ID3D11Device* dev, Shader* shader) {
|
||||
Mesh* rock_mesh = mesh_create_cube(dev);
|
||||
Material* rock_mat = material_create(shader, NULL);
|
||||
rock_mat->color = (Vec4){0.55f, 0.50f, 0.45f, 1.0f};
|
||||
|
||||
Mesh* trunk_mesh = mesh_create_cube(dev);
|
||||
Material* trunk_mat = material_create(shader, NULL);
|
||||
trunk_mat->color = (Vec4){0.55f, 0.40f, 0.25f, 1.0f};
|
||||
|
||||
Mesh* leaves_mesh = mesh_create_sphere(dev, 1.0f, 8);
|
||||
Material* leaves_mat = material_create(shader, NULL);
|
||||
leaves_mat->color = (Vec4){0.22f, 0.65f, 0.28f, 1.0f};
|
||||
|
||||
for (int i = 0; i < MAX_SCATTER; i++) {
|
||||
float x = ((float)rand() / (float)RAND_MAX) * 400.0f - 200.0f;
|
||||
float z = ((float)rand() / (float)RAND_MAX) * 400.0f - 200.0f;
|
||||
float h = terrain_manager_get_height(g_terrain, x, z);
|
||||
// 跳过过低(水)或过高的山顶
|
||||
if (h < -2.0f || h > 20.0f) continue;
|
||||
|
||||
int type = rand() % 3;
|
||||
if (type == 0) {
|
||||
// 岩石
|
||||
float s = 1.0f + ((float)rand() / (float)RAND_MAX) * 2.0f;
|
||||
Vec3 pos = {x, h + s * 0.3f, z};
|
||||
Vec3 sc = {s, s * 0.6f, s};
|
||||
add_scatter(rock_mesh, rock_mat, pos, sc);
|
||||
} else {
|
||||
// 树
|
||||
float trunk_h = 1.5f + ((float)rand() / (float)RAND_MAX) * 1.5f;
|
||||
Vec3 trunk_pos = {x, h + trunk_h * 0.5f, z};
|
||||
Vec3 trunk_sc = {0.25f, trunk_h, 0.25f};
|
||||
add_scatter(trunk_mesh, trunk_mat, trunk_pos, trunk_sc);
|
||||
|
||||
float leaves_s = 1.2f + ((float)rand() / (float)RAND_MAX) * 1.2f;
|
||||
Vec3 leaves_pos = {x, h + trunk_h + leaves_s * 0.4f, z};
|
||||
Vec3 leaves_sc = {leaves_s, leaves_s, leaves_s};
|
||||
add_scatter(leaves_mesh, leaves_mat, leaves_pos, leaves_sc);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("Generated %d scatter instances", g_scatter_count);
|
||||
}
|
||||
|
||||
static void render_scatter(Renderer* r, const Vec4 planes[6]) {
|
||||
const float cull_distance = 140.0f;
|
||||
const float cull_dist2 = cull_distance * cull_distance;
|
||||
int rendered = 0;
|
||||
for (int i = 0; i < g_scatter_count; i++) {
|
||||
ScatterInstance* s = &g_scatter[i];
|
||||
Vec3 pos = {s->world.m[3][0], s->world.m[3][1], s->world.m[3][2]};
|
||||
Vec3 d;
|
||||
vec3_sub(&pos, &g_camera.position, &d);
|
||||
if (vec3_dot(&d, &d) > cull_dist2) continue;
|
||||
|
||||
// 视锥剔除:用包围球近似
|
||||
float radius = fmaxf(fmaxf(s->world.m[0][0], s->world.m[1][1]), s->world.m[2][2]) * 0.866f;
|
||||
if (!frustum_intersects_sphere(planes, pos, radius)) continue;
|
||||
|
||||
renderer_draw_mesh_with_material(r, s->mesh, s->mat, &s->world);
|
||||
rendered++;
|
||||
}
|
||||
LOG_INFO("Scatter render: visible=%d/%d", rendered, g_scatter_count);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 地形高度回调
|
||||
// ============================================================================
|
||||
static float get_terrain_height(float x, float z, void* user) {
|
||||
(void)user;
|
||||
if (g_terrain) return terrain_manager_get_height(g_terrain, x, z);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 引擎回调
|
||||
// ============================================================================
|
||||
static void on_render(Engine* engine) {
|
||||
Renderer* r = engine_get_renderer(engine);
|
||||
GraphicsDevice* dev = engine_get_graphics_device(engine);
|
||||
if (!r || !dev) return;
|
||||
|
||||
renderer_set_view(r, camera_get_view(&g_camera));
|
||||
renderer_set_projection(r, camera_get_projection(&g_camera));
|
||||
|
||||
renderer_begin_frame(r);
|
||||
|
||||
Mat4 vp;
|
||||
renderer_get_view_projection(r, &vp);
|
||||
Vec4 planes[6];
|
||||
frustum_from_matrix(&vp, planes);
|
||||
|
||||
if (g_water) {
|
||||
Mat4 water_world;
|
||||
mat4_identity(&water_world);
|
||||
water_world.m[3][1] = -5.0f;
|
||||
renderer_draw_mesh_with_material(r, g_water, g_water_mat, &water_world);
|
||||
}
|
||||
|
||||
if (g_terrain) {
|
||||
terrain_manager_update(g_terrain, g_camera.position);
|
||||
terrain_manager_render(g_terrain, r);
|
||||
}
|
||||
|
||||
render_scatter(r, planes);
|
||||
|
||||
if (g_test_scene) {
|
||||
scene_update(g_test_scene);
|
||||
scene_render(g_test_scene, r);
|
||||
}
|
||||
|
||||
renderer_end_frame(r);
|
||||
|
||||
if (engine->frame_count == 60) {
|
||||
graphics_device_save_screenshot(dev, "open_world_screenshot1.bmp");
|
||||
}
|
||||
if (engine->frame_count == 180) {
|
||||
graphics_device_save_screenshot(dev, "open_world_screenshot2.bmp");
|
||||
}
|
||||
}
|
||||
|
||||
static void on_update(Engine* engine, double dt) {
|
||||
(void)engine;
|
||||
float fdt = (float)dt;
|
||||
|
||||
Vec3 dir = {0.0f, 0.0f, 0.0f};
|
||||
if (GetAsyncKeyState('W') & 0x8000) dir.z += 1.0f;
|
||||
if (GetAsyncKeyState('S') & 0x8000) dir.z -= 1.0f;
|
||||
if (GetAsyncKeyState('A') & 0x8000) dir.x -= 1.0f;
|
||||
if (GetAsyncKeyState('D') & 0x8000) dir.x += 1.0f;
|
||||
|
||||
if (!g_walk_mode) {
|
||||
if (GetAsyncKeyState(VK_SPACE) & 0x8000) dir.y += 1.0f;
|
||||
if (GetAsyncKeyState(VK_SHIFT) & 0x8000) dir.y -= 1.0f;
|
||||
}
|
||||
|
||||
if (dir.x != 0.0f || dir.y != 0.0f || dir.z != 0.0f) {
|
||||
camera_controller_move(&g_controller, dir, fdt);
|
||||
}
|
||||
|
||||
camera_controller_update(&g_controller, fdt);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
(void)engine;
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
|
||||
// 切换步行/飞行模式
|
||||
if (key == 'F' || key == 'f') {
|
||||
g_walk_mode = !g_walk_mode;
|
||||
camera_controller_set_mode(&g_controller, g_walk_mode ? CAMERA_MODE_WALK : CAMERA_MODE_FLY);
|
||||
g_controller.move_speed = g_walk_mode ? 8.0f : 40.0f;
|
||||
LOG_INFO("Camera mode: %s (speed %.1f)", g_walk_mode ? "walk" : "fly", g_controller.move_speed);
|
||||
}
|
||||
|
||||
// 模式切换后重新定位相机高度
|
||||
if (g_walk_mode) {
|
||||
float ground = get_terrain_height(g_camera.position.x, g_camera.position.z, NULL);
|
||||
g_camera.position.y = ground + g_controller.height_offset;
|
||||
g_camera.target.y = g_camera.position.y + sinf(g_controller.pitch);
|
||||
g_camera.dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void on_mouse_move(Engine* engine, int x, int y) {
|
||||
(void)engine;
|
||||
if (g_mouse_down[0]) { // 左键拖拽旋转
|
||||
if (g_mouse_first) {
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
g_mouse_first = 0;
|
||||
} else {
|
||||
float dx = (float)(x - g_last_mouse_x);
|
||||
float dy = (float)(y - g_last_mouse_y);
|
||||
camera_controller_look(&g_controller, dx, dy);
|
||||
g_last_mouse_x = x;
|
||||
g_last_mouse_y = y;
|
||||
}
|
||||
} 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;
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
EngineConfig config = engine_default_config();
|
||||
config.app_name = "Lity3D - Open World Demo";
|
||||
config.vsync = 1;
|
||||
config.window_width = 1280;
|
||||
config.window_height = 720;
|
||||
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &config)) {
|
||||
LOG_FATAL("Engine 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 load failed");
|
||||
return -1;
|
||||
}
|
||||
LOG_INFO("Shader loaded via AssetManager");
|
||||
|
||||
Shader* default_shader = (Shader*)asset_data(g_shader_asset);
|
||||
|
||||
// 地形材质
|
||||
g_terrain_mat = material_create(default_shader, NULL);
|
||||
g_terrain_mat->color = (Vec4){1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
// 参照立方体
|
||||
g_cube = mesh_create_cube(dev->device);
|
||||
g_cube_mat = material_create(default_shader, NULL);
|
||||
g_cube_mat->color = (Vec4){1.0f, 0.2f, 0.2f, 1.0f};
|
||||
|
||||
// 水面(不透明,作为低洼处背景)
|
||||
g_water = mesh_create_plane(dev->device, 2000.0f);
|
||||
g_water_mat = material_create(default_shader, NULL);
|
||||
g_water_mat->color = (Vec4){0.18f, 0.45f, 0.78f, 1.0f};
|
||||
|
||||
// 测试场景:仅保留一个红色立方体作为原点标记
|
||||
g_test_scene = (Scene*)calloc(1, sizeof(Scene));
|
||||
scene_init(g_test_scene);
|
||||
|
||||
SceneNode* cube_node = scene_create_node(g_test_scene, "cube");
|
||||
scene_set_parent(cube_node, g_test_scene->root);
|
||||
cube_node->position = (Vec3){0.0f, 0.0f, 0.0f};
|
||||
MeshRenderer* cube_mr = mesh_renderer_create(MESH_CUBE, g_cube, g_cube_mat);
|
||||
scene_node_set_mesh_renderer(cube_node, cube_mr);
|
||||
|
||||
// 地形配置
|
||||
TerrainConfig tcfg = terrain_default_config();
|
||||
tcfg.vertices_per_chunk = 48;
|
||||
tcfg.chunk_size = 64.0f;
|
||||
tcfg.height_scale = 30.0f;
|
||||
tcfg.uv_scale = 0.05f;
|
||||
|
||||
g_terrain = terrain_manager_create(dev->device, &tcfg, g_terrain_mat);
|
||||
g_terrain->load_radius = 3;
|
||||
|
||||
// 生成植被/岩石
|
||||
generate_scatter(dev->device, default_shader);
|
||||
|
||||
// 天空色与柔和环境光
|
||||
renderer_set_clear_color(r, 0.53f, 0.81f, 0.98f, 1.0f);
|
||||
renderer_set_light(r, (Vec3){0.5f, -1.0f, 0.3f},
|
||||
(Vec4){0.55f, 0.53f, 0.48f, 1.0f},
|
||||
(Vec4){0.70f, 0.74f, 0.82f, 1.0f});
|
||||
|
||||
// 相机初始化:站在地形上,朝 +Z
|
||||
float aspect = (float)config.window_width / (float)config.window_height;
|
||||
g_camera = camera_perspective(1.0472f, aspect, 0.1f, 500.0f);
|
||||
float start_h = terrain_manager_get_height(g_terrain, 0.0f, 0.0f);
|
||||
g_camera.position = (Vec3){0.0f, start_h + 1.75f, 0.0f};
|
||||
g_camera.target = (Vec3){0.0f, start_h + 1.75f, 5.0f};
|
||||
g_camera.far_z = 500.0f;
|
||||
g_camera.dirty = 1;
|
||||
|
||||
g_controller = camera_controller_create(&g_camera);
|
||||
g_controller.move_speed = 8.0f;
|
||||
g_controller.mouse_sensitivity = 0.004f;
|
||||
camera_controller_set_ground_callback(&g_controller, get_terrain_height, NULL);
|
||||
g_walk_mode = 1;
|
||||
camera_controller_set_mode(&g_controller, CAMERA_MODE_WALK);
|
||||
LOG_INFO("Starting in walk mode at height %.2f", start_h);
|
||||
|
||||
renderer_set_view(r, camera_get_view(&g_camera));
|
||||
renderer_set_projection(r, camera_get_projection(&g_camera));
|
||||
|
||||
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("Running open world demo...");
|
||||
engine_run(engine);
|
||||
|
||||
terrain_manager_destroy(g_terrain);
|
||||
if (g_test_scene) {
|
||||
scene_destroy_renderers(g_test_scene);
|
||||
scene_destroy(g_test_scene);
|
||||
free(g_test_scene);
|
||||
}
|
||||
if (g_cube) mesh_destroy(g_cube);
|
||||
asset_manager_destroy(g_assets);
|
||||
engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// raw3d_test.c - 用 draw_quad 画 3D 方块,验证场景图变换
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static Scene g_scene;
|
||||
static float g_time = 0;
|
||||
|
||||
typedef struct { float p[3],n[3],uv[2],c[4]; } V;
|
||||
static void draw_quad_3d(ID3D11DeviceContext* ctx, float x, float y, float w, float h, float r, float g, float b, float a) {
|
||||
V v[4] = {{{x,y,0},{0,0,-1},{0,0},{r,g,b,a}},{{x+w,y,0},{0,0,-1},{1,0},{r,g,b,a}},{{x+w,y+h,0},{0,0,-1},{1,1},{r,g,b,a}},{{x,y+h,0},{0,0,-1},{0,1},{r,g,b,a}}};
|
||||
uint32_t idx[6] = {0,1,2,0,2,3};
|
||||
ID3D11Buffer *vb=NULL,*ib=NULL;
|
||||
D3D11_BUFFER_DESC bd={}; D3D11_SUBRESOURCE_DATA sd={};
|
||||
bd.ByteWidth=sizeof(V)*4; bd.Usage=D3D11_USAGE_DEFAULT; bd.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&vb);
|
||||
bd.ByteWidth=sizeof(uint32_t)*6; bd.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd,&sd,&ib);
|
||||
UINT stride=sizeof(V),off=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&stride,&off);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib->lpVtbl->Release(ib); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
scene_update(&g_scene);
|
||||
g_time += (float)engine->delta_time;
|
||||
|
||||
float sw=(float)g_dev->width, sh=(float)g_dev->height;
|
||||
float fov=1.0f/tanf(0.4f), asp=sw/sh;
|
||||
|
||||
// VP矩阵: 摄像机在(8,5,10)看原点
|
||||
float ex=8,ey=5,ez=10;
|
||||
float fx=-ex,fy=-ey,fz=-ez, fl=sqrtf(fx*fx+fy*fy+fz*fz); fx/=fl;fy/=fl;fz/=fl;
|
||||
float rx=fy*0-fz*1,ry=fz*0-fx*0,rz=fx*1-fy*0;
|
||||
float rl=sqrtf(rx*rx+ry*ry+rz*rz);rx/=rl;ry/=rl;rz/=rl;
|
||||
float ux=ry*fz-rz*fy,uy=rz*fx-rx*fz,uz=rx*fy-ry*fx;
|
||||
float mvp[16];
|
||||
mvp[0]=rx*fov/asp;mvp[1]=ry*fov/asp;mvp[2]=rz*fov/asp;mvp[3]=0;
|
||||
mvp[4]=ux*fov;mvp[5]=uy*fov;mvp[6]=uz*fov;mvp[7]=0;
|
||||
mvp[8]=fx;mvp[9]=fy;mvp[10]=fz;mvp[11]=0;
|
||||
mvp[12]=-(rx*ex+ry*ey+rz*ez)*fov/asp;
|
||||
mvp[13]=-(ux*ex+uy*ey+uz*ez)*fov;
|
||||
mvp[14]=-(fx*ex+fy*ey+fz*ez);mvp[15]=1;
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
D3D11_VIEWPORT vp={};vp.Width=sw;vp.Height=sh;vp.MaxDepth=1;
|
||||
ctx->lpVtbl->RSSetViewports(ctx,1,&vp);
|
||||
D3D11_RASTERIZER_DESC rd={};rd.FillMode=D3D11_FILL_SOLID;rd.CullMode=D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rs=NULL;
|
||||
g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device,&rd,&rs);
|
||||
ctx->lpVtbl->RSSetState(ctx,rs);
|
||||
D3D11_DEPTH_STENCIL_DESC dsd={};dsd.DepthEnable=FALSE;
|
||||
ID3D11DepthStencilState* dss=NULL;
|
||||
g_dev->device->lpVtbl->CreateDepthStencilState(g_dev->device,&dsd,&dss);
|
||||
ctx->lpVtbl->OMSetDepthStencilState(ctx,dss,0);
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx,D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
|
||||
// 地面
|
||||
shader_set_matrix(g_shader, ctx, mvp);
|
||||
draw_quad_3d(ctx, -5, 0, 10, 10, 0.3f, 0.35f, 0.4f, 1);
|
||||
|
||||
// 场景节点
|
||||
for (int i=0;i<g_scene.node_count;i++) {
|
||||
SceneNode*n=&g_scene.nodes[i];
|
||||
if (!n->visible||n->id==0||n->user_type!=1) continue;
|
||||
// 用世界矩阵变换4个角点
|
||||
float corners[4][3] = {{-0.5f,-0.5f,0},{0.5f,-0.5f,0},{0.5f,0.5f,0},{-0.5f,0.5f,0}};
|
||||
V v[4]; uint32_t idx[6]={0,1,2,0,2,3};
|
||||
float colors[][3]={{1,0.2f,0.2f},{0.2f,1,0.2f},{0.2f,0.2f,1},{1,1,0.2f},{0.5f,0.2f,0.8f},{0.2f,0.8f,0.8f},{0.8f,0.5f,0.2f},{0.5f,0.5f,0.5f}};
|
||||
int ci=(i-1)%8;
|
||||
for(int c=0;c<4;c++){
|
||||
float px=0,py=0,pz=0;
|
||||
for(int r=0;r<4;r++) {float wc=n->world_matrix.m[0][r]*corners[c][0]+n->world_matrix.m[1][r]*corners[c][1]+n->world_matrix.m[2][r]*corners[c][2]+n->world_matrix.m[3][r]; px+=wc*mvp[r*4+0]; py+=wc*mvp[r*4+1]; pz+=wc*mvp[r*4+2];}
|
||||
// 简化: 直接用世界坐标+投影
|
||||
float wx=n->world_matrix.m[3][0]+corners[c][0];
|
||||
float wy=n->world_matrix.m[3][1]+corners[c][1];
|
||||
float wz=n->world_matrix.m[3][2]+corners[c][2];
|
||||
v[c].p[0]=wx; v[c].p[1]=wy; v[c].p[2]=wz;
|
||||
v[c].n[0]=0; v[c].n[1]=0; v[c].n[2]=1;
|
||||
v[c].c[0]=colors[ci][0]; v[c].c[1]=colors[ci][1]; v[c].c[2]=colors[ci][2]; v[c].c[3]=1;
|
||||
}
|
||||
ID3D11Buffer* vb=NULL,*ib2=NULL;
|
||||
D3D11_BUFFER_DESC bd2={}; D3D11_SUBRESOURCE_DATA sd2={};
|
||||
bd2.ByteWidth=sizeof(V)*4; bd2.Usage=D3D11_USAGE_DEFAULT; bd2.BindFlags=D3D11_BIND_VERTEX_BUFFER;
|
||||
sd2.pSysMem=v; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&vb);
|
||||
bd2.ByteWidth=sizeof(uint32_t)*6; bd2.BindFlags=D3D11_BIND_INDEX_BUFFER;
|
||||
sd2.pSysMem=idx; g_dev->device->lpVtbl->CreateBuffer(g_dev->device,&bd2,&sd2,&ib2);
|
||||
UINT s2=sizeof(V),o2=0;
|
||||
ctx->lpVtbl->IASetVertexBuffers(ctx,0,1,&vb,&s2,&o2);
|
||||
ctx->lpVtbl->IASetIndexBuffer(ctx,ib2,DXGI_FORMAT_R32_UINT,0);
|
||||
ctx->lpVtbl->DrawIndexed(ctx,6,0,0);
|
||||
ib2->lpVtbl->Release(ib2); vb->lpVtbl->Release(vb);
|
||||
}
|
||||
|
||||
if(rs) rs->lpVtbl->Release(rs);
|
||||
if(dss) dss->lpVtbl->Release(dss);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if (key==VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int) {
|
||||
EngineConfig cfg=engine_default_config(); cfg.app_name="lity3d Raw3D";
|
||||
Engine* e=engine_create(); if(!engine_init(e,&cfg))return -1;
|
||||
g_dev=graphics_device_create();
|
||||
if(!graphics_device_init(g_dev,window_get_handle(e->window),cfg.window_width,cfg.window_height,1))return -1;
|
||||
g_shader=shader_create(); shader_compile(g_shader,g_dev->device,NULL,NULL,0,0);
|
||||
scene_init(&g_scene);
|
||||
SceneNode* c1=scene_create_node(&g_scene,"Cube1"); scene_set_position(c1,0,0.5f,0); c1->user_type=1;
|
||||
SceneNode* c2=scene_create_node(&g_scene,"Cube2"); scene_set_position(c2,-3,0.5f,2); c2->user_type=1;
|
||||
SceneNode* c3=scene_create_node(&g_scene,"Cube3"); scene_set_position(c3,3,0.5f,-2); scene_set_scale(c3,0.5f,0.5f,0.5f); c3->user_type=1;
|
||||
SceneNode* ch=scene_create_node(&g_scene,"Child"); scene_set_position(ch,2,0,0); ch->user_type=1; scene_set_parent(ch,c1);
|
||||
engine_set_render_callback(e,on_render); engine_set_key_callback(e,on_key);
|
||||
engine_run(e);
|
||||
shader_destroy(g_shader); graphics_device_destroy(g_dev); engine_shutdown(e);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
// scene_test.c - 场景图 + 网格渲染
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Rendering/shader.h"
|
||||
#include "../Engine/Rendering/mesh.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
static Shader* g_shader = NULL;
|
||||
static Mesh* g_cube = NULL;
|
||||
static Mesh* g_plane = NULL;
|
||||
static Scene g_scene;
|
||||
static SceneNode* g_camera = NULL;
|
||||
static float g_time = 0;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
scene_update(&g_scene);
|
||||
g_time += (float)engine->delta_time;
|
||||
|
||||
float sw = (float)g_dev->width, sh = (float)g_dev->height;
|
||||
float fov = 1.0f / tanf(0.5f * 0.785f), aspect = sw / sh;
|
||||
Vec3 cam_pos;
|
||||
scene_get_world_position(g_camera, &cam_pos);
|
||||
|
||||
// VP 矩阵
|
||||
float proj[16] = {0};
|
||||
proj[0] = fov / aspect; proj[5] = -fov;
|
||||
proj[10] = 1.0f; proj[11] = -1.0f; proj[14] = 0.1f; proj[15] = 1.0f;
|
||||
|
||||
Vec3 eye = cam_pos, target = {0,0,0}, up = {0,1,0};
|
||||
Vec3 f, r, u;
|
||||
vec3_sub(&target, &eye, &f); vec3_normalize(&f, &f);
|
||||
vec3_cross(&up, &f, &r); vec3_normalize(&r, &r);
|
||||
vec3_cross(&f, &r, &u);
|
||||
|
||||
float view[16] = {0};
|
||||
view[0]=r.x; view[1]=u.x; view[2]=-f.x;
|
||||
view[4]=r.y; view[5]=u.y; view[6]=-f.y;
|
||||
view[8]=r.z; view[9]=u.z; view[10]=-f.z;
|
||||
view[12]=-vec3_dot(&r,&eye); view[13]=-vec3_dot(&u,&eye); view[14]=vec3_dot(&f,&eye); view[15]=1.0f;
|
||||
|
||||
float vp_raw[16] = {0};
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
vp_raw[i*4+j] = view[i*4+0]*proj[0*4+j]+view[i*4+1]*proj[1*4+j]+view[i*4+2]*proj[2*4+j]+view[i*4+3]*proj[3*4+j];
|
||||
Mat4 vp_m, vp_t;
|
||||
memcpy(&vp_m, vp_raw, sizeof(Mat4));
|
||||
mat4_transpose(&vp_m, &vp_t);
|
||||
|
||||
graphics_device_clear(g_dev, 0.15f, 0.18f, 0.25f, 1.0f);
|
||||
|
||||
D3D11_VIEWPORT vport = {0}; vport.Width = sw; vport.Height = sh; vport.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vport);
|
||||
|
||||
D3D11_RASTERIZER_DESC rdesc = {0}; rdesc.FillMode = D3D11_FILL_SOLID; rdesc.CullMode = D3D11_CULL_NONE;
|
||||
ID3D11RasterizerState* rstate = NULL;
|
||||
g_dev->device->lpVtbl->CreateRasterizerState(g_dev->device, &rdesc, &rstate);
|
||||
ctx->lpVtbl->RSSetState(ctx, rstate);
|
||||
|
||||
ctx->lpVtbl->IASetPrimitiveTopology(ctx, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
shader_bind(g_shader, ctx);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&vp_t);
|
||||
|
||||
if (g_plane) mesh_draw(g_plane, ctx);
|
||||
|
||||
for (int i = 0; i < g_scene.node_count; i++) {
|
||||
SceneNode* node = &g_scene.nodes[i];
|
||||
if (!node->visible || node->id == 0 || node->user_type != 1 || !g_cube) continue;
|
||||
float wvp_raw[16] = {0};
|
||||
for (int r2 = 0; r2 < 4; r2++)
|
||||
for (int c = 0; c < 4; c++)
|
||||
wvp_raw[r2*4+c] = view[r2*4+0]*node->world_matrix.m[0][c]+view[r2*4+1]*node->world_matrix.m[1][c]+view[r2*4+2]*node->world_matrix.m[2][c]+view[r2*4+3]*node->world_matrix.m[3][c];
|
||||
Mat4 wvp_m, wvp_t;
|
||||
memcpy(&wvp_m, wvp_raw, sizeof(Mat4));
|
||||
mat4_transpose(&wvp_m, &wvp_t);
|
||||
shader_set_matrix(g_shader, ctx, (float*)&wvp_t);
|
||||
mesh_draw(g_cube, ctx);
|
||||
}
|
||||
|
||||
if (rstate) rstate->lpVtbl->Release(rstate);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) { if (key == VK_ESCAPE) engine_request_quit(engine); }
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) {
|
||||
(void)hI;(void)hP;(void)cmd;(void)nS;
|
||||
EngineConfig cfg = engine_default_config();
|
||||
cfg.app_name = "lity3d Scene Test";
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &cfg)) return -1;
|
||||
g_dev = graphics_device_create();
|
||||
if (!graphics_device_init(g_dev, window_get_handle(engine->window), cfg.window_width, cfg.window_height, 1)) return -1;
|
||||
g_shader = shader_create();
|
||||
shader_compile(g_shader, g_dev->device, NULL, NULL, 0, 0);
|
||||
g_cube = mesh_create_cube(g_dev->device);
|
||||
g_plane = mesh_create_plane(g_dev->device, 10.0f);
|
||||
scene_init(&g_scene);
|
||||
g_camera = scene_create_node(&g_scene, "Camera");
|
||||
scene_set_position(g_camera, 5, 4, 8);
|
||||
SceneNode* c1 = scene_create_node(&g_scene, "Cube1");
|
||||
scene_set_position(c1, 0, 0.5f, 0); c1->user_type = 1;
|
||||
SceneNode* c2 = scene_create_node(&g_scene, "Cube2");
|
||||
scene_set_position(c2, -3, 0.5f, 2); c2->user_type = 1;
|
||||
SceneNode* c3 = scene_create_node(&g_scene, "Cube3");
|
||||
scene_set_position(c3, 3, 0.5f, -2); c3->user_type = 1; scene_set_scale(c3, 0.5f, 0.5f, 0.5f);
|
||||
SceneNode* child = scene_create_node(&g_scene, "Child");
|
||||
scene_set_position(child, 2, 0, 0); child->user_type = 1; scene_set_parent(child, c1);
|
||||
engine_set_render_callback(engine, on_render);
|
||||
engine_set_key_callback(engine, on_key);
|
||||
engine_run(engine);
|
||||
mesh_destroy(g_cube); mesh_destroy(g_plane); shader_destroy(g_shader);
|
||||
graphics_device_destroy(g_dev); engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// scene_test2.c - 最小化场景测试
|
||||
#include "../Engine/Core/engine.h"
|
||||
#include "../Engine/Core/logger.h"
|
||||
#include "../Engine/Window/window.h"
|
||||
#include "../Engine/Rendering/graphics_device.h"
|
||||
#include "../Engine/Scene/scene_graph.h"
|
||||
#include "../Engine/include/engine_api.h"
|
||||
#include "../Engine/ASM/math_c_fallback.h"
|
||||
|
||||
static GraphicsDevice* g_dev = NULL;
|
||||
|
||||
static void on_render(Engine* engine) {
|
||||
if (!g_dev) return;
|
||||
ID3D11DeviceContext* ctx = g_dev->context;
|
||||
float clear[4] = {0.2f, 0.3f, 0.5f, 1.0f};
|
||||
g_dev->context->lpVtbl->ClearRenderTargetView(g_dev->context, g_dev->render_target, clear);
|
||||
|
||||
D3D11_VIEWPORT vp = {0};
|
||||
vp.Width = (float)g_dev->width; vp.Height = (float)g_dev->height;
|
||||
vp.MaxDepth = 1.0f;
|
||||
ctx->lpVtbl->RSSetViewports(ctx, 1, &vp);
|
||||
graphics_device_present(g_dev);
|
||||
}
|
||||
|
||||
static void on_key(Engine* engine, int key) {
|
||||
if (key == VK_ESCAPE) engine_request_quit(engine);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR cmd, int nS) {
|
||||
(void)hI;(void)hP;(void)cmd;(void)nS;
|
||||
LOG_INFO("=== lity3d Scene Test ===");
|
||||
EngineConfig cfg = engine_default_config();
|
||||
cfg.app_name = "lity3d Scene Test";
|
||||
Engine* engine = engine_create();
|
||||
if (!engine_init(engine, &cfg)) return -1;
|
||||
g_dev = graphics_device_create();
|
||||
if (!graphics_device_init(g_dev, window_get_handle(engine->window), cfg.window_width, cfg.window_height, 1)) return -1;
|
||||
LOG_INFO("D3D11 ready");
|
||||
Scene scene; scene_init(&scene);
|
||||
SceneNode* n1 = scene_create_node(&scene, "A");
|
||||
scene_set_position(n1, 1, 0, 0);
|
||||
SceneNode* n2 = scene_create_node(&scene, "B");
|
||||
scene_set_parent(n2, n1);
|
||||
scene_set_position(n2, 0, 2, 0);
|
||||
scene_update(&scene);
|
||||
LOG_INFO("A world pos: (%.1f,%.1f,%.1f)", scene.nodes[1].world_matrix.m[3][0], scene.nodes[1].world_matrix.m[3][1], scene.nodes[1].world_matrix.m[3][2]);
|
||||
LOG_INFO("B world pos: (%.1f,%.1f,%.1f)", scene.nodes[2].world_matrix.m[3][0], scene.nodes[2].world_matrix.m[3][1], scene.nodes[2].world_matrix.m[3][2]);
|
||||
engine_set_render_callback(engine, on_render);
|
||||
engine_set_key_callback(engine, on_key);
|
||||
engine_run(engine);
|
||||
graphics_device_destroy(g_dev);
|
||||
engine_shutdown(engine);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# lity3d 积木脚本 - 测试解释器
|
||||
# 开始 -> 移动物体 -> 打印 -> 循环3次 -> 移动物体
|
||||
|
||||
[B]
|
||||
id=1
|
||||
name=开始
|
||||
p=100,100
|
||||
c=0
|
||||
|
||||
[B]
|
||||
id=2
|
||||
name=移动物体
|
||||
p=350,100
|
||||
c=1
|
||||
|
||||
[B]
|
||||
id=3
|
||||
name=打印
|
||||
p=600,100
|
||||
d=Hello World
|
||||
c=3
|
||||
|
||||
[B]
|
||||
id=4
|
||||
name=循环
|
||||
p=100,250
|
||||
d=3
|
||||
c=2
|
||||
|
||||
[B]
|
||||
id=5
|
||||
name=移动物体
|
||||
p=350,250
|
||||
c=1
|
||||
|
||||
# 连线: 开始.输出0 -> 移动物体.执行0
|
||||
[W]
|
||||
a=10000
|
||||
b=20000
|
||||
|
||||
# 移动物体.执行0 -> 打印.执行0
|
||||
[W]
|
||||
a=20000
|
||||
b=30000
|
||||
|
||||
# 打印.执行0 -> 循环.执行0
|
||||
[W]
|
||||
a=30000
|
||||
b=40000
|
||||
|
||||
# 循环.执行0 -> 移动物体2.执行0
|
||||
[W]
|
||||
a=40000
|
||||
b=50000
|
||||
Reference in new issue
Block a user