fixed game export; Lua API - support methods returning structures, e.g. RenderModuleImpl::getCameraRay
This commit is contained in:
parent
47e344b302
commit
a2567f98db
|
@ -41,8 +41,8 @@ declare ImGui: {
|
|||
NewLine : () -> (),
|
||||
NextColumn : () -> (),
|
||||
OpenPopup : (string) -> (),
|
||||
PlotLines : (string, {number}, Vec2) -> (),
|
||||
PopItemWidth : () -> (),
|
||||
PlotLines : (string, {number}, Vec2) -> (),
|
||||
PopItemWidth : () -> (),
|
||||
PopID : () -> (),
|
||||
PopStyleColor : (number) -> (),
|
||||
PopStyleVar : (number) -> (),
|
||||
|
@ -97,8 +97,19 @@ end
|
|||
declare class SweepHit
|
||||
position : Vec3
|
||||
normal : Vec3
|
||||
entity : Entity
|
||||
distance : number
|
||||
entity : Entity
|
||||
end
|
||||
|
||||
declare class Ray
|
||||
origin : any
|
||||
dir : Vec3
|
||||
end
|
||||
|
||||
declare class RayCastModelHit
|
||||
is_hit : boolean
|
||||
t : number
|
||||
entity : Entity
|
||||
end
|
||||
|
||||
declare class GUISystem
|
||||
|
@ -118,7 +129,7 @@ end
|
|||
|
||||
declare class Model
|
||||
getBoneCount : (Model) -> number
|
||||
getBoneName : (Model, number) -> string
|
||||
getBoneName : (Model, number) -> any --[[char]]
|
||||
getBoneParent : (Model, number) -> number
|
||||
end
|
||||
|
||||
|
@ -134,7 +145,7 @@ end
|
|||
declare class gui_module
|
||||
getRectAt : (gui_module, Vec2) -> Entity?
|
||||
isOver : (gui_module, Vec2, Entity?) -> boolean
|
||||
getSystem : (gui_module) -> any --[[GUISystem *]]
|
||||
getSystem : (gui_module) -> GUISystem
|
||||
end
|
||||
|
||||
declare class lua_script_module
|
||||
|
@ -154,6 +165,7 @@ declare class renderer_module
|
|||
addDebugCross : (renderer_module, DVec3, number, Color) -> ()
|
||||
addDebugLine : (renderer_module, DVec3, DVec3, Color) -> ()
|
||||
addDebugTriangle : (renderer_module, DVec3, DVec3, DVec3, Color) -> ()
|
||||
castRay : (renderer_module, any --[[void*]], Entity?) -> any --[[RayCastModelHit]]
|
||||
setActiveCamera : (renderer_module, Entity?) -> ()
|
||||
end
|
||||
|
||||
|
@ -207,6 +219,7 @@ declare class camera_component
|
|||
far: number
|
||||
orthographic: boolean
|
||||
orthographic_size: number
|
||||
getRay : (camera_component, Vec2) -> any --[[Ray]]
|
||||
end
|
||||
|
||||
declare class decal_component
|
||||
|
@ -248,7 +261,7 @@ declare class model_instance_component
|
|||
enabled: boolean
|
||||
material: string
|
||||
source: string
|
||||
getModel : (model_instance_component) -> any --[[Model *]]
|
||||
getModel : (model_instance_component) -> Model
|
||||
end
|
||||
|
||||
declare class environment_probe_component
|
||||
|
@ -446,7 +459,7 @@ declare class navmesh_zone_component
|
|||
drawNavmesh : (navmesh_zone_component, DVec3, boolean, boolean, boolean) -> ()
|
||||
drawCompactHeightfield : (navmesh_zone_component) -> ()
|
||||
drawHeightfield : (navmesh_zone_component) -> ()
|
||||
generateNavmesh : (navmesh_zone_component) -> any --[[NavmeshBuildJob *]]
|
||||
generateNavmesh : (navmesh_zone_component) -> any --[[NavmeshBuildJob]]
|
||||
end
|
||||
|
||||
declare class lua_script_inline_component
|
||||
|
@ -585,6 +598,8 @@ declare Editor: {
|
|||
declare LumixAPI: {
|
||||
RaycastHit : { create : () -> RaycastHit, destroy : (RaycastHit) -> () },
|
||||
SweepHit : { create : () -> SweepHit, destroy : (SweepHit) -> () },
|
||||
Ray : { create : () -> Ray, destroy : (Ray) -> () },
|
||||
RayCastModelHit : { create : () -> RayCastModelHit, destroy : (RayCastModelHit) -> () },
|
||||
|
||||
INPUT_KEYCODE_SHIFT: number,
|
||||
INPUT_KEYCODE_LEFT : number,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "engine/thread.h"
|
||||
#include "engine/world.h"
|
||||
#include "gui/gui_system.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "lua_script/lua_script_system.h"
|
||||
#include "renderer/pipeline.h"
|
||||
#include "renderer/render_module.h"
|
||||
|
@ -79,7 +80,7 @@ struct Runner final
|
|||
m_viewport.rot = Quat::IDENTITY;
|
||||
|
||||
m_renderer = static_cast<Renderer*>(m_engine->getSystemManager().getSystem("renderer"));
|
||||
PipelineResource* pres = m_engine->getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = m_engine->getResourceManager().load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_pipeline = Pipeline::create(*m_renderer, pres, "APP");
|
||||
|
||||
while (m_engine->getFileSystem().hasWork()) {
|
||||
|
|
|
@ -165,6 +165,8 @@ struct AssetBrowserImpl : AssetBrowser {
|
|||
}
|
||||
|
||||
~AssetBrowserImpl() override {
|
||||
removePlugin(m_world_asset_plugin);
|
||||
m_app.getAssetCompiler().removePlugin(m_world_asset_plugin);
|
||||
m_app.removeAction(&m_focus_search);
|
||||
m_app.removeAction(&m_toggle_ui);
|
||||
m_app.removeAction(&m_back_action);
|
||||
|
|
|
@ -551,12 +551,12 @@ struct AssetCompilerImpl : AssetCompiler {
|
|||
|| fs.getLastModified(dst_path) < fs.getLastModified(meta_path)
|
||||
)
|
||||
{
|
||||
if (!getPlugin(res.getPath())) return ResourceManagerHub::LoadHook::Action::IMMEDIATE;
|
||||
if (!m_init_finished) {
|
||||
res.incRefCount();
|
||||
m_on_init_load.push(&res);
|
||||
return ResourceManagerHub::LoadHook::Action::DEFERRED;
|
||||
}
|
||||
if (!getPlugin(res.getPath())) return ResourceManagerHub::LoadHook::Action::IMMEDIATE;
|
||||
|
||||
pushToCompileQueue(Path(filepath));
|
||||
return ResourceManagerHub::LoadHook::Action::DEFERRED;
|
||||
|
|
|
@ -35,10 +35,13 @@ struct LUMIX_EDITOR_API AssetCompiler {
|
|||
virtual void addPlugin(IPlugin& plugin, Span<const char*> extensions) = 0;
|
||||
virtual void removePlugin(IPlugin& plugin) = 0;
|
||||
virtual bool compile(const Path& path) = 0;
|
||||
// load meta for `res` and returns it as lua_State*. Must call lua_close on the state after you are done using it.
|
||||
virtual lua_State* getMeta(const Path& res) = 0;
|
||||
virtual void updateMeta(const Path& resource, Span<const u8> data) const = 0;
|
||||
virtual const HashMap<FilePathHash, ResourceItem>& lockResources() = 0;
|
||||
virtual void unlockResources() = 0;
|
||||
// register non-`Resource` dependency, so we reload dependants in case something changes
|
||||
// `Resource` dependencies are automatically handled elsewhere
|
||||
virtual void registerDependency(const Path& included_from, const Path& dependency) = 0;
|
||||
virtual void addResource(ResourceType type, const Path& path) = 0;
|
||||
virtual bool writeCompiledResource(const Path& path, Span<const u8> data) = 0;
|
||||
|
|
|
@ -152,14 +152,12 @@ Axis collide(const ScaleGizmo& gizmo, const WorldView& view, const Gizmo::Config
|
|||
const float scale = getScale(vp, gizmo.pos, cfg.scale);
|
||||
|
||||
const Vec3 pos(gizmo.pos - vp.pos);
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Vec2 mp = view.getMousePos();
|
||||
vp.getRay(mp, origin, dir);
|
||||
const Vec3 rel_origin = Vec3(origin - vp.pos);
|
||||
const float x_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + gizmo.x);
|
||||
const float y_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + gizmo.y);
|
||||
const float z_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + gizmo.z);
|
||||
const Ray ray = vp.getRay(mp);
|
||||
const Vec3 rel_origin = Vec3(ray.origin - vp.pos);
|
||||
const float x_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + gizmo.x);
|
||||
const float y_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + gizmo.y);
|
||||
const float z_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + gizmo.z);
|
||||
|
||||
float influenced_dist = scale * INFLUENCE_DISTANCE;
|
||||
|
||||
|
@ -173,33 +171,31 @@ Axis collide(const RotationGizmo& gizmo, const WorldView& view, const Gizmo::Con
|
|||
const Vec3 pos(gizmo.pos - vp.pos);
|
||||
const float scale = getScale(vp, gizmo.pos, cfg.scale);
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Viewport viewport = view.getViewport();
|
||||
const Vec2 mp = view.getMousePos();
|
||||
viewport.getRay(mp, origin, dir);
|
||||
const Vec3 rel_origin(origin - vp.pos);
|
||||
const Ray ray = viewport.getRay(mp);
|
||||
const Vec3 rel_origin(ray.origin - vp.pos);
|
||||
|
||||
float t;
|
||||
float mint = FLT_MAX;
|
||||
float d = FLT_MAX;
|
||||
Axis axis = Axis::NONE;
|
||||
if (getRayPlaneIntersecion(rel_origin, dir, pos, normalize(gizmo.x), t) && t > 0) {
|
||||
const Vec3 p = rel_origin + dir * t;
|
||||
if (getRayPlaneIntersecion(rel_origin, ray.dir, pos, normalize(gizmo.x), t) && t > 0) {
|
||||
const Vec3 p = rel_origin + ray.dir * t;
|
||||
mint = t;
|
||||
d = length(p - pos);
|
||||
axis = Axis::X;
|
||||
}
|
||||
|
||||
if (getRayPlaneIntersecion(rel_origin, dir, pos, normalize(gizmo.y), t) && t < mint && t > 0) {
|
||||
const Vec3 p = rel_origin + dir * t;
|
||||
if (getRayPlaneIntersecion(rel_origin, ray.dir, pos, normalize(gizmo.y), t) && t < mint && t > 0) {
|
||||
const Vec3 p = rel_origin + ray.dir * t;
|
||||
d = length(p - pos);
|
||||
mint = t;
|
||||
axis = Axis::Y;
|
||||
}
|
||||
|
||||
if (getRayPlaneIntersecion(rel_origin, dir, pos, normalize(gizmo.z), t) && t < mint && t > 0) {
|
||||
const Vec3 p = rel_origin + dir * t;
|
||||
if (getRayPlaneIntersecion(rel_origin, ray.dir, pos, normalize(gizmo.z), t) && t < mint && t > 0) {
|
||||
const Vec3 p = rel_origin + ray.dir * t;
|
||||
d = length(p - pos);
|
||||
axis = Axis::Z;
|
||||
}
|
||||
|
@ -209,27 +205,25 @@ Axis collide(const RotationGizmo& gizmo, const WorldView& view, const Gizmo::Con
|
|||
}
|
||||
|
||||
Axis collide(const TranslationGizmo& gizmo, const Transform& tr, const WorldView& view, const Gizmo::Config& cfg) {
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Viewport viewport = view.getViewport();
|
||||
const Vec2 mp = view.getMousePos();
|
||||
viewport.getRay(mp, origin, dir);
|
||||
const Ray ray = viewport.getRay(mp);
|
||||
|
||||
const Vec3 rel_origin(origin - viewport.pos);
|
||||
const Vec3 rel_origin(ray.origin - viewport.pos);
|
||||
float t, tmin = FLT_MAX;
|
||||
const Vec3 pos(gizmo.pos - viewport.pos);
|
||||
bool hit = getRayTriangleIntersection(rel_origin, dir, pos, pos + gizmo.x * 0.5f, pos + gizmo.y * 0.5f, &t);
|
||||
bool hit = getRayTriangleIntersection(rel_origin, ray.dir, pos, pos + gizmo.x * 0.5f, pos + gizmo.y * 0.5f, &t);
|
||||
Axis transform_axis = Axis::NONE;
|
||||
if (hit) {
|
||||
tmin = t;
|
||||
transform_axis = Axis::XY;
|
||||
}
|
||||
hit = getRayTriangleIntersection(rel_origin, dir, pos, pos + gizmo.y * 0.5f, pos + gizmo.z * 0.5f, &t);
|
||||
hit = getRayTriangleIntersection(rel_origin, ray.dir, pos, pos + gizmo.y * 0.5f, pos + gizmo.z * 0.5f, &t);
|
||||
if (hit && t < tmin) {
|
||||
tmin = t;
|
||||
transform_axis = Axis::YZ;
|
||||
}
|
||||
hit = getRayTriangleIntersection(rel_origin, dir, pos, pos + gizmo.x * 0.5f, pos + gizmo.z * 0.5f, &t);
|
||||
hit = getRayTriangleIntersection(rel_origin, ray.dir, pos, pos + gizmo.x * 0.5f, pos + gizmo.z * 0.5f, &t);
|
||||
if (hit && t < tmin) transform_axis = Axis::XZ;
|
||||
|
||||
if (transform_axis != Axis::NONE) return transform_axis;
|
||||
|
@ -239,9 +233,9 @@ Axis collide(const TranslationGizmo& gizmo, const Transform& tr, const WorldView
|
|||
const Vec3 x = is_global ? gizmo.x : tr.rot.rotate(Vec3(scale, 0, 0));
|
||||
const Vec3 y = is_global ? gizmo.y : tr.rot.rotate(Vec3(0, scale, 0));
|
||||
const Vec3 z = is_global ? gizmo.z : tr.rot.rotate(Vec3(0, 0, scale));
|
||||
const float x_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + x);
|
||||
const float y_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + y);
|
||||
const float z_dist = getLineSegmentDistance(rel_origin, dir, pos, pos + z);
|
||||
const float x_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + x);
|
||||
const float y_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + y);
|
||||
const float z_dist = getLineSegmentDistance(rel_origin, ray.dir, pos, pos + z);
|
||||
|
||||
const float influenced_dist = length(gizmo.x) * INFLUENCE_DISTANCE;
|
||||
if (x_dist < y_dist && x_dist < z_dist && x_dist < influenced_dist) return Axis::X;
|
||||
|
@ -252,10 +246,8 @@ Axis collide(const TranslationGizmo& gizmo, const Transform& tr, const WorldView
|
|||
template <typename Gizmo>
|
||||
DVec3 getMousePlaneIntersection(const WorldView& view, const Gizmo& gizmo, Axis transform_axis) {
|
||||
const Viewport& vp = view.getViewport();
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Vec2 mouse_pos = view.getMousePos();
|
||||
vp.getRay(mouse_pos, origin, dir);
|
||||
const Ray ray = vp.getRay(mouse_pos);
|
||||
bool is_two_axed = transform_axis == Axis::XZ || transform_axis == Axis::XY || transform_axis == Axis::YZ;
|
||||
if (is_two_axed) {
|
||||
Vec3 plane_normal;
|
||||
|
@ -266,11 +258,11 @@ DVec3 getMousePlaneIntersection(const WorldView& view, const Gizmo& gizmo, Axis
|
|||
default: ASSERT(false); break;
|
||||
}
|
||||
float t;
|
||||
const Vec3 rel_origin = Vec3(origin - gizmo.pos);
|
||||
if (getRayPlaneIntersecion(rel_origin, dir, Vec3(0), plane_normal, t)) {
|
||||
return origin + dir * t;
|
||||
const Vec3 rel_origin = Vec3(ray.origin - gizmo.pos);
|
||||
if (getRayPlaneIntersecion(rel_origin, ray.dir, Vec3(0), plane_normal, t)) {
|
||||
return ray.origin + ray.dir * t;
|
||||
}
|
||||
return origin;
|
||||
return ray.origin;
|
||||
}
|
||||
|
||||
Vec3 axis;
|
||||
|
@ -280,8 +272,8 @@ DVec3 getMousePlaneIntersection(const WorldView& view, const Gizmo& gizmo, Axis
|
|||
case Axis::Z: axis = normalize(gizmo.z); break;
|
||||
default: ASSERT(false); return DVec3(0);
|
||||
}
|
||||
const Vec3 normal = cross(cross(dir, axis), dir);
|
||||
const float d = dot(Vec3(origin - gizmo.pos), normal) / dot(axis, normal);
|
||||
const Vec3 normal = cross(cross(ray.dir, axis), ray.dir);
|
||||
const float d = dot(Vec3(ray.origin - gizmo.pos), normal) / dot(axis, normal);
|
||||
return gizmo.pos + axis * d;
|
||||
}
|
||||
|
||||
|
@ -725,16 +717,14 @@ bool box(u64 id, WorldView& view, Transform& tr, Vec3& half_extents, const Confi
|
|||
const Viewport vp = view.getViewport();
|
||||
const float scale = getScale(vp, tr.pos, cfg.scale) * 0.1f;
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Vec2 mp = view.getMousePos();
|
||||
vp.getRay(mp, origin, dir);
|
||||
const Ray ray = vp.getRay(mp);
|
||||
|
||||
const Vec3 pos = Vec3(origin - tr.pos);
|
||||
const Vec3 pos = Vec3(ray.origin - tr.pos);
|
||||
const Vec3 center = Vec3(tr.pos - vp.pos);
|
||||
auto cube = [&](u32 color, Vec3 p, float& prev_t){
|
||||
float t;
|
||||
if (getRaySphereIntersection(pos, dir, p, scale * 1.414f, t) && (prev_t < 0 || t < prev_t)) {
|
||||
if (getRaySphereIntersection(pos, ray.dir, p, scale * 1.414f, t) && (prev_t < 0 || t < prev_t)) {
|
||||
renderCube(view, SELECTED_COLOR, center + p, scale, xn, yn, zn);
|
||||
WorldView::Vertex* line = view.render(true, 2);
|
||||
line[0].pos = center;
|
||||
|
|
|
@ -18,7 +18,7 @@ struct RenderInterface {
|
|||
virtual ImTextureID loadTexture(const struct Path& path) = 0;
|
||||
virtual bool isValid(ImTextureID texture) = 0;
|
||||
virtual void unloadTexture(ImTextureID handle) = 0;
|
||||
virtual WorldView::RayHit castRay(World& world, const DVec3& origin, const Vec3& dir, EntityPtr ignored) = 0;
|
||||
virtual WorldView::RayHit castRay(World& world, const struct Ray& ray, EntityPtr ignored) = 0;
|
||||
virtual Path getModelInstancePath(World& world, EntityRef entity) = 0;
|
||||
virtual bool saveTexture(Engine& engine, const char* path_cstr, const void* pixels, int w, int h, bool upper_left_origin) = 0;
|
||||
};
|
||||
|
|
|
@ -34,15 +34,13 @@ struct SplineEditorPlugin : SplineEditor, StudioApp::MousePlugin, PropertyGrid::
|
|||
World* world = m_app.getWorldEditor().getWorld();
|
||||
const EntityRef e = *getSplineEntity();
|
||||
const Transform tr = world->getTransform(e);
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Viewport& vp = view.getViewport();
|
||||
vp.getRay(Vec2((float)x, (float)y), origin, dir);
|
||||
const Ray ray = vp.getRay(Vec2((float)x, (float)y));
|
||||
|
||||
for (const Vec3& point : spline->points) {
|
||||
const DVec3 p = tr.pos + point;
|
||||
float t;
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), dir, Vec3(p - vp.pos), 0.1f, t);
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), ray.dir, Vec3(p - vp.pos), 0.1f, t);
|
||||
if (hovered) return true;
|
||||
}
|
||||
|
||||
|
@ -59,10 +57,8 @@ struct SplineEditorPlugin : SplineEditor, StudioApp::MousePlugin, PropertyGrid::
|
|||
}
|
||||
|
||||
void onMouseUp(WorldView& view, int x, int y, os::MouseButton button) override {
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
const Viewport& vp = view.getViewport();
|
||||
vp.getRay(Vec2((float)x, (float)y), origin, dir);
|
||||
const Ray ray = vp.getRay(Vec2((float)x, (float)y));
|
||||
|
||||
const EntityRef e = *getSplineEntity();
|
||||
World* world = m_app.getWorldEditor().getWorld();
|
||||
|
@ -73,7 +69,7 @@ struct SplineEditorPlugin : SplineEditor, StudioApp::MousePlugin, PropertyGrid::
|
|||
for (const Vec3& point : spline->points) {
|
||||
const DVec3 p = tr.pos + point;
|
||||
float t;
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), dir, Vec3(p - vp.pos), 0.1f, t);
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), ray.dir, Vec3(p - vp.pos), 0.1f, t);
|
||||
if (hovered) {
|
||||
m_selected = i32(&point - spline->points.begin());
|
||||
return;
|
||||
|
@ -213,13 +209,11 @@ struct SplineEditorPlugin : SplineEditor, StudioApp::MousePlugin, PropertyGrid::
|
|||
const Transform& tr = world.getTransform(e);
|
||||
const DVec3 cam_pos = view.getViewport().pos;
|
||||
const Vec3 offset = Vec3(tr.pos - cam_pos);
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
view.getViewport().getRay(view.getMousePos(), origin, dir);
|
||||
const Ray ray = view.getViewport().getRay(view.getMousePos());
|
||||
for (i32 i = 0; i < spline.points.size(); ++i) {
|
||||
const DVec3 p = tr.pos + spline.points[i];
|
||||
float t;
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), dir, Vec3(p - cam_pos), 0.1f, t);
|
||||
const bool hovered = getRaySphereIntersection(Vec3(0), ray.dir, Vec3(p - cam_pos), 0.1f, t);
|
||||
addCircle(view, p, 0.1f, tr.rot.rotate(Vec3(0, 1, 0)), hovered ? Color::RED : Color::GREEN);
|
||||
}
|
||||
|
||||
|
|
|
@ -1194,12 +1194,12 @@ struct StudioAppImpl final : StudioApp
|
|||
|
||||
for (EntityRef entity : selected) {
|
||||
const DVec3 origin = world->getPosition(entity);
|
||||
auto hit = getRenderInterface()->castRay(*world, origin, Vec3(0, -1, 0), entity);
|
||||
auto hit = getRenderInterface()->castRay(*world, Ray{origin, Vec3(0, -1, 0)}, entity);
|
||||
if (hit.is_hit) {
|
||||
new_positions.push(origin + Vec3(0, -hit.t, 0));
|
||||
}
|
||||
else {
|
||||
hit = getRenderInterface()->castRay(*world, origin, Vec3(0, 1, 0), entity);
|
||||
hit = getRenderInterface()->castRay(*world, Ray{origin, Vec3(0, 1, 0)}, entity);
|
||||
if (hit.is_hit) {
|
||||
new_positions.push(origin + Vec3(0, hit.t, 0));
|
||||
}
|
||||
|
@ -3105,8 +3105,6 @@ struct StudioAppImpl final : StudioApp
|
|||
os::FileIterator* iter = m_engine->getFileSystem().createFileIterator(".lumix/resources");
|
||||
const char* base_path = m_engine->getFileSystem().getBasePath();
|
||||
os::FileInfo info;
|
||||
exportDataScan("pipelines/", infos);
|
||||
exportDataScan("universes/", infos);
|
||||
exportFile("lumix.prj", infos);
|
||||
while (os::getNextFile(iter, &info)) {
|
||||
if (info.is_directory) continue;
|
||||
|
@ -3123,6 +3121,8 @@ struct StudioAppImpl final : StudioApp
|
|||
catString(rec.path, info.filename);
|
||||
infos.insert(rec.hash, rec);
|
||||
}
|
||||
exportDataScan("pipelines/", infos);
|
||||
exportDataScan("universes/", infos);
|
||||
|
||||
os::destroyFileIterator(iter);
|
||||
}
|
||||
|
@ -3188,9 +3188,6 @@ struct StudioAppImpl final : StudioApp
|
|||
void exportDataScanResources(AssociativeArray<FilePathHash, ExportFileInfo>& infos)
|
||||
{
|
||||
ResourceManagerHub& rm = m_engine->getResourceManager();
|
||||
exportDataScan("scripts/", infos);
|
||||
exportDataScan("pipelines/", infos);
|
||||
exportDataScan("universes/", infos);
|
||||
exportFile("lumix.prj", infos);
|
||||
for (auto iter = rm.getAll().begin(), end = rm.getAll().end(); iter != end; ++iter) {
|
||||
const auto& resources = iter.value()->getResourceTable();
|
||||
|
@ -3198,13 +3195,17 @@ struct StudioAppImpl final : StudioApp
|
|||
const FilePathHash hash = res->getPath().getHash();
|
||||
const Path baked_path(".lumix/resources/", hash, ".res");
|
||||
|
||||
auto& out_info = infos.emplace(hash);
|
||||
copyString(Span(out_info.path), baked_path);
|
||||
out_info.hash = hash;
|
||||
out_info.size = os::getFileSize(baked_path);
|
||||
out_info.offset = ~0UL;
|
||||
if (infos.find(hash) < 0) {
|
||||
auto& out_info = infos.emplace(hash);
|
||||
copyString(Span(out_info.path), baked_path);
|
||||
out_info.hash = hash;
|
||||
out_info.size = os::getFileSize(baked_path);
|
||||
out_info.offset = ~0UL;
|
||||
}
|
||||
}
|
||||
}
|
||||
exportDataScan("pipelines/", infos);
|
||||
exportDataScan("universes/", infos);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -709,13 +709,14 @@ Matrix Viewport::getViewRotation() const
|
|||
}
|
||||
|
||||
|
||||
void Viewport::getRay(const Vec2& screen_pos, DVec3& origin, Vec3& dir) const
|
||||
Ray Viewport::getRay(const Vec2& screen_pos) const
|
||||
{
|
||||
origin = pos;
|
||||
Ray ray;
|
||||
ray.origin = pos;
|
||||
|
||||
if (w <= 0 || h <= 0) {
|
||||
dir = rot.rotate(Vec3(0, 0, 1));
|
||||
return;
|
||||
ray.dir = rot.rotate(Vec3(0, 0, 1));
|
||||
return ray;
|
||||
}
|
||||
|
||||
const float nx = 2 * (screen_pos.x / w) - 1;
|
||||
|
@ -727,19 +728,20 @@ void Viewport::getRay(const Vec2& screen_pos, DVec3& origin, Vec3& dir) const
|
|||
const Vec3 x = rot * Vec3(1, 0, 0);
|
||||
const Vec3 y = rot * Vec3(0, 1, 0);
|
||||
float ratio = h > 0 ? w / (float)h : 1;
|
||||
origin += x * nx * ortho_size * ratio
|
||||
ray.origin += x * nx * ortho_size * ratio
|
||||
+ y * ny * ortho_size;
|
||||
}
|
||||
|
||||
const Matrix view_matrix = getView(origin);
|
||||
const Matrix view_matrix = getView(ray.origin);
|
||||
const Matrix inverted = (projection_matrix * view_matrix).inverted();
|
||||
|
||||
Vec4 p0 = inverted * Vec4(nx, ny, -1, 1);
|
||||
Vec4 p1 = inverted * Vec4(nx, ny, 1, 1);
|
||||
p0 *= 1 / p0.w;
|
||||
p1 *= 1 / p1.w;
|
||||
dir = normalize((p1 - p0).xyz());
|
||||
if (is_ortho) dir *= -1.f;
|
||||
ray.dir = normalize((p1 - p0).xyz());
|
||||
if (is_ortho) ray.dir *= -1.f;
|
||||
return ray;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ struct LUMIX_ENGINE_API Viewport {
|
|||
ShiftedFrustum getFrustum() const;
|
||||
ShiftedFrustum getFrustum(const Vec2& viewport_min_px, const Vec2& viewport_max_px) const;
|
||||
Vec2 worldToScreenPixels(const DVec3& world) const;
|
||||
void getRay(const Vec2& screen_pos, DVec3& origin, Vec3& dir) const;
|
||||
Ray getRay(const Vec2& screen_pos) const;
|
||||
|
||||
bool is_ortho;
|
||||
float fov;
|
||||
|
|
|
@ -468,14 +468,14 @@ static i32 LUA_getNextModule(lua_State* L) {
|
|||
|
||||
i32 LUA_getThisTypeName(lua_State* L) {
|
||||
reflection::FunctionBase* fn = LuaWrapper::checkArg<reflection::FunctionBase*>(L, 1);
|
||||
StringView sv = fn->getThisTypeName();
|
||||
StringView sv = fn->getThisType().type_name;
|
||||
lua_pushlstring(L, sv.begin, sv.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
i32 LUA_getReturnTypeName(lua_State* L) {
|
||||
reflection::FunctionBase* fn = LuaWrapper::checkArg<reflection::FunctionBase*>(L, 1);
|
||||
StringView sv = fn->getReturnTypeName();
|
||||
StringView sv = fn->getReturnType().type_name;
|
||||
lua_pushlstring(L, sv.begin, sv.size());
|
||||
return 1;
|
||||
}
|
||||
|
@ -561,7 +561,7 @@ static u32 LUA_getFunctionArgCount(reflection::FunctionBase* fnc) {
|
|||
|
||||
static i32 LUA_getFunctionReturnType(lua_State* L) {
|
||||
auto* fnc = LuaWrapper::checkArg<reflection::FunctionBase*>(L, 1);
|
||||
StringView name = fnc->getReturnTypeName();
|
||||
StringView name = fnc->getReturnType().type_name;
|
||||
lua_pushlstring(L, name.begin, name.size());
|
||||
return 1;
|
||||
}
|
||||
|
@ -805,14 +805,6 @@ static int LUA_loadWorld(lua_State* L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int finishrequire(lua_State* L)
|
||||
{
|
||||
if (lua_isstring(L, -1))
|
||||
lua_error(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int LUA_loadstring(lua_State* L) {
|
||||
const char* src = LuaWrapper::checkArg<const char*>(L, 1);
|
||||
size_t bytecode_size;
|
||||
|
@ -832,71 +824,6 @@ static int LUA_loadstring(lua_State* L) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int LUA_require(lua_State* L) {
|
||||
const char* name = luaL_checkstring(L, 1);
|
||||
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1);
|
||||
|
||||
// return the module from the cache
|
||||
lua_getfield(L, -1, name);
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
// L stack: _MODULES result
|
||||
return finishrequire(L);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
Engine* engine = LuaWrapper::getClosureObject<Engine>(L);
|
||||
Path path(name, ".lua");
|
||||
OutputMemoryStream blob(engine->getAllocator());
|
||||
if (!engine->getFileSystem().getContentSync(path, blob)) {
|
||||
luaL_argerrorL(L, 1, "error loading module");
|
||||
}
|
||||
|
||||
// module needs to run in a new thread, isolated from the rest
|
||||
// note: we create ML on main thread so that it doesn't inherit environment of L
|
||||
lua_State* GL = lua_mainthread(L);
|
||||
lua_State* ML = lua_newthread(GL);
|
||||
lua_xmove(GL, L, 1);
|
||||
|
||||
// new thread needs to have the globals sandboxed
|
||||
luaL_sandboxthread(ML);
|
||||
|
||||
// now we can compile & run module on the new thread
|
||||
size_t bytecode_size;
|
||||
char* bytecode = luau_compile((const char*)blob.data(), blob.size(), nullptr, &bytecode_size);
|
||||
if (luau_load(ML, name, bytecode, bytecode_size, 0) == 0)
|
||||
{
|
||||
int status = lua_resume(ML, L, 0);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
if (lua_gettop(ML) == 0)
|
||||
lua_pushstring(ML, "module must return a value");
|
||||
else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1))
|
||||
lua_pushstring(ML, "module must return a table or function");
|
||||
}
|
||||
else if (status == LUA_YIELD)
|
||||
{
|
||||
lua_pushstring(ML, "module can not yield");
|
||||
}
|
||||
else if (!lua_isstring(ML, -1))
|
||||
{
|
||||
lua_pushstring(ML, "unknown error while running module");
|
||||
}
|
||||
}
|
||||
free(bytecode);
|
||||
|
||||
// there's now a return value on top of ML; L stack: _MODULES ML
|
||||
lua_xmove(ML, L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -4, name);
|
||||
|
||||
// L stack: _MODULES ML result
|
||||
return finishrequire(L);
|
||||
}
|
||||
|
||||
static int LUA_instantiatePrefab(lua_State* L) {
|
||||
Engine* engine = LuaWrapper::getClosureObject<Engine>(L);
|
||||
LuaWrapper::checkTableArg(L, 1);
|
||||
|
@ -927,8 +854,6 @@ static int LUA_instantiatePrefab(lua_State* L) {
|
|||
void registerEngineAPI(lua_State* L, Engine* engine)
|
||||
{
|
||||
lua_pushlightuserdata(L, engine);
|
||||
lua_pushcclosure(L, &LUA_require, "require", 1);
|
||||
lua_setglobal(L, "require");
|
||||
|
||||
lua_pushcfunction(L, &LUA_loadstring, "loadstring");
|
||||
lua_setglobal(L, "loadstring");
|
||||
|
|
|
@ -71,7 +71,6 @@ bool pcall(lua_State* L, int nargs, int nres)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool execute(lua_State* L
|
||||
, StringView content
|
||||
, const char* name
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Lumix {
|
|||
struct World;
|
||||
struct CameraParams;
|
||||
struct PipelineTexture;
|
||||
template <typename T> struct Array;
|
||||
|
||||
namespace LuaWrapper {
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ template <typename T> struct IsSame<T, T> { static constexpr bool Value = true;
|
|||
template <typename T> struct RemoveReference { using Type = T; };
|
||||
template <typename T> struct RemoveReference<T&> { using Type = T; };
|
||||
template <typename T> struct RemoveReference<T&&> { using Type = T; };
|
||||
template <typename T> struct RemovePointerHelper { using Type = T; };
|
||||
template <typename T> struct RemovePointerHelper<T*> { using Type = T; };
|
||||
template <typename T> struct RemoveConst { using Type = T; };
|
||||
template <typename T> struct RemoveConst<const T> { using Type = T; };
|
||||
template <typename T> struct RemoveConst<const T&> { using Type = T; };
|
||||
|
@ -16,6 +18,7 @@ template <typename T> struct RemoveVolatile { using Type = T; };
|
|||
template <typename T> struct RemoveVolatile<volatile T> { using Type = T; };
|
||||
template <typename T> using RemoveCR = typename RemoveConst<typename RemoveReference<T>::Type>::Type;
|
||||
template <typename T> using RemoveCVR = typename RemoveVolatile<RemoveCR<T>>::Type;
|
||||
template <typename T> using RemovePointer = typename RemovePointerHelper<T>::Type;
|
||||
|
||||
template <int... T> struct Indices {};
|
||||
|
||||
|
|
|
@ -7,13 +7,22 @@
|
|||
#include "engine/string.h"
|
||||
#include "engine/world.h"
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
namespace Lumix::reflection {
|
||||
|
||||
namespace detail {
|
||||
|
||||
StringView normalizeTypeName(StringView type_name) {
|
||||
StringView res = type_name;
|
||||
if (startsWith(res, "struct ")) res.removePrefix(7);
|
||||
if (startsWith(res, "Lumix::")) res.removePrefix(7);
|
||||
while (res.size() > 0 && res[0] == ' ') res.removePrefix(1);
|
||||
while (res.size() > 0 && res.back() == ' ') res.removeSuffix(1);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
namespace reflection
|
||||
{
|
||||
|
||||
struct Context {
|
||||
Module* first_module = nullptr;
|
||||
RegisteredComponent component_bases[ComponentType::MAX_TYPES_COUNT];
|
||||
|
@ -298,7 +307,4 @@ void ArrayProperty::visitChildren(struct IPropertyVisitor& visitor) const {
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace Reflection
|
||||
|
||||
|
||||
} // namespace Lumix
|
||||
} // namespace Lumix::reflection
|
||||
|
|
|
@ -307,6 +307,8 @@ struct GetTypeNameHelper
|
|||
}
|
||||
};
|
||||
|
||||
LUMIX_ENGINE_API StringView normalizeTypeName(StringView type_name);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
|
@ -321,7 +323,7 @@ const IAttribute* getAttribute(const Property<T>& prop, IAttribute::Type type) {
|
|||
template <typename T>
|
||||
StringView getTypeName()
|
||||
{
|
||||
return detail::GetTypeNameHelper<T>::GetTypeName();
|
||||
return detail::normalizeTypeName(detail::GetTypeNameHelper<T>::GetTypeName());
|
||||
}
|
||||
|
||||
struct Variant {
|
||||
|
@ -372,9 +374,14 @@ struct Variant {
|
|||
};
|
||||
|
||||
struct TypeDescriptor {
|
||||
using Copier = void* (*)(const void* src, IAllocator& allocator);
|
||||
Variant::Type type;
|
||||
StringView type_name;
|
||||
bool is_const;
|
||||
bool is_reference;
|
||||
bool is_pointer;
|
||||
u32 size;
|
||||
Copier create_copy;
|
||||
};
|
||||
|
||||
template <typename T> struct VariantTag {};
|
||||
|
@ -399,9 +406,23 @@ template <typename T> inline Variant::Type getVariantType() { return _getVariant
|
|||
|
||||
template <typename T> TypeDescriptor toTypeDescriptor() {
|
||||
TypeDescriptor td;
|
||||
td.create_copy = [](const void* src, IAllocator& allocator) -> void* {
|
||||
if constexpr (__is_constructible(T)) {
|
||||
return LUMIX_NEW(allocator, RemoveCVR<T>)(*(RemoveCVR<T>*)src);
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
td.type_name = getTypeName<RemoveCVR<RemovePointer<T>>>();
|
||||
td.type = getVariantType<T>();
|
||||
td.is_const = !IsSame<T, typename RemoveConst<T>::Type>::Value;
|
||||
td.is_reference = !IsSame<T, typename RemoveReference<T>::Type>::Value;
|
||||
td.is_pointer = !IsSame<T, RemovePointer<T>>::Value;
|
||||
if constexpr (IsSame<T, void>::Value) {
|
||||
td.size = 0;
|
||||
}
|
||||
else {
|
||||
td.size = sizeof(T);
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
|
@ -411,10 +432,9 @@ struct FunctionBase
|
|||
|
||||
virtual u32 getArgCount() const = 0;
|
||||
virtual TypeDescriptor getReturnType() const = 0;
|
||||
virtual StringView getReturnTypeName() const = 0;
|
||||
virtual StringView getThisTypeName() const = 0;
|
||||
virtual TypeDescriptor getThisType() const = 0;
|
||||
virtual TypeDescriptor getArgType(int i) const = 0;
|
||||
virtual Variant invoke(void* obj, Span<Variant> args) const = 0;
|
||||
virtual void invoke(void* obj, Span<u8> ret_mem, Span<Variant> args) const = 0;
|
||||
virtual bool isConstMethod() = 0;
|
||||
|
||||
const char* decl_code;
|
||||
|
@ -441,18 +461,16 @@ template <typename T> inline T& fromVariant(int i, Span<Variant> args, VariantTa
|
|||
template <typename... Args>
|
||||
struct VariantCaller {
|
||||
template <typename C, typename F, int... I>
|
||||
static Variant call(C* inst, F f, Span<Variant> args, Indices<I...>& indices) {
|
||||
static void call(C* inst, F f, Span<u8> ret_mem, Span<Variant> args, Indices<I...>& indices) {
|
||||
using R = typename ResultOf<F>::Type;
|
||||
if constexpr (IsSame<R, void>::Value) {
|
||||
Variant v;
|
||||
v.type = Variant::VOID;
|
||||
(inst->*f)(fromVariant(I, args, VariantTag<RemoveCVR<Args>>{})...);
|
||||
return v;
|
||||
}
|
||||
else {
|
||||
Variant v;
|
||||
v = (inst->*f)(fromVariant(I, args, VariantTag<RemoveCVR<Args>>{})...);
|
||||
return v;
|
||||
auto v = (inst->*f)(fromVariant(I, args, VariantTag<RemoveCVR<Args>>{})...);
|
||||
if (ret_mem.length() == sizeof(v)) {
|
||||
memcpy(ret_mem.m_begin, &v, sizeof(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -522,8 +540,7 @@ struct Function<R (C::*)(Args...)> : FunctionBase
|
|||
|
||||
u32 getArgCount() const override { return sizeof...(Args); }
|
||||
TypeDescriptor getReturnType() const override { return toTypeDescriptor<R>(); }
|
||||
StringView getReturnTypeName() const override { return getTypeName<R>(); }
|
||||
StringView getThisTypeName() const override { return getTypeName<C>(); }
|
||||
TypeDescriptor getThisType() const override { return toTypeDescriptor<C>(); }
|
||||
bool isConstMethod() override { return false; }
|
||||
|
||||
TypeDescriptor getArgType(int i) const override
|
||||
|
@ -535,9 +552,9 @@ struct Function<R (C::*)(Args...)> : FunctionBase
|
|||
return expand[i];
|
||||
}
|
||||
|
||||
Variant invoke(void* obj, Span<Variant> args) const override {
|
||||
void invoke(void* obj, Span<u8> ret_mem, Span<Variant> args) const override {
|
||||
auto indices = typename BuildIndices<-1, sizeof...(Args)>::result{};
|
||||
return VariantCaller<Args...>::call((C*)obj, function, args, indices);
|
||||
VariantCaller<Args...>::call((C*)obj, function, ret_mem, args, indices);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -549,8 +566,7 @@ struct Function<R (C::*)(Args...) const> : FunctionBase
|
|||
|
||||
u32 getArgCount() const override { return sizeof...(Args); }
|
||||
TypeDescriptor getReturnType() const override { return toTypeDescriptor<R>(); }
|
||||
StringView getReturnTypeName() const override { return getTypeName<R>(); }
|
||||
StringView getThisTypeName() const override { return getTypeName<C>(); }
|
||||
TypeDescriptor getThisType() const override { return toTypeDescriptor<C>(); }
|
||||
bool isConstMethod() override { return true; }
|
||||
|
||||
TypeDescriptor getArgType(int i) const override
|
||||
|
@ -562,9 +578,9 @@ struct Function<R (C::*)(Args...) const> : FunctionBase
|
|||
return expand[i];
|
||||
}
|
||||
|
||||
Variant invoke(void* obj, Span<Variant> args) const override {
|
||||
void invoke(void* obj, Span<u8> ret_mem, Span<Variant> args) const override {
|
||||
auto indices = typename BuildIndices<-1, sizeof...(Args)>::result{};
|
||||
return VariantCaller<Args...>::call((const C*)obj, function, args, indices);
|
||||
VariantCaller<Args...>::call((const C*)obj, function, ret_mem, args, indices);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "engine/world.h"
|
||||
#include "gui/gui_module.h"
|
||||
#include "gui/sprite.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "renderer/draw2d.h"
|
||||
#include "renderer/gpu/gpu.h"
|
||||
#include "renderer/pipeline.h"
|
||||
|
@ -244,7 +245,7 @@ public:
|
|||
void init() {
|
||||
Engine& engine = m_app.getEngine();
|
||||
Renderer& renderer = *static_cast<Renderer*>(engine.getSystemManager().getSystem("renderer"));
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/gui_editor.pln"));
|
||||
LuaScript* pres = engine.getResourceManager().load<LuaScript>(Path("pipelines/gui_editor.lua"));
|
||||
m_pipeline = Pipeline::create(renderer, pres, "");
|
||||
}
|
||||
|
||||
|
|
|
@ -649,6 +649,60 @@ struct EditorWindow : AssetEditorWindow {
|
|||
#endif
|
||||
};
|
||||
|
||||
static bool gatherRequires(Span<const u8> src, Lumix::Array<Path>& dependencies) {
|
||||
lua_State* L = luaL_newstate();
|
||||
|
||||
auto reg_dep = [](lua_State* L) -> int {
|
||||
lua_getglobal(L, "__deps");
|
||||
Lumix::Array<Path>* deps = (Lumix::Array<Path>*)lua_tolightuserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
const char* path = LuaWrapper::checkArg<const char*>(L, 1);
|
||||
Path lua_path(path, ".lua");
|
||||
deps->push(lua_path);
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto index_fn = [](lua_State* L) -> int {
|
||||
lua_insert(L, 1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
auto call_fn = [](lua_State* L) -> int {
|
||||
lua_insert(L, 1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
lua_pushcclosure(L, reg_dep, "require", 0);
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, "require");
|
||||
|
||||
lua_pushlightuserdata(L, &dependencies);
|
||||
lua_setfield(L, LUA_GLOBALSINDEX, "__deps");
|
||||
|
||||
lua_newtable(L); // metatable
|
||||
lua_pushcfunction(L, index_fn, "__index"); // metatable, fn
|
||||
lua_setfield(L, -2, "__index"); // metatable
|
||||
|
||||
lua_pushcfunction(L, call_fn, "__call"); // metatable, fn
|
||||
lua_setfield(L, -2, "__call"); // metatable
|
||||
|
||||
lua_newtable(L); // metatable, new_g
|
||||
lua_getglobal(L, "require"); // metatable, new_g, require
|
||||
lua_setfield(L, -2, "require"); // metatable, new_g
|
||||
|
||||
lua_insert(L, -2); // new_g, meta
|
||||
lua_setmetatable(L, -2); //new_g
|
||||
|
||||
bool errors = LuaWrapper::luaL_loadbuffer(L, (const char*)src.m_begin, src.length(), "gather_requires"); // new_g, fn
|
||||
if (errors) {
|
||||
lua_close(L);
|
||||
return false;
|
||||
}
|
||||
lua_insert(L, -2); // fn, new_g
|
||||
lua_setfenv(L, -2);
|
||||
const bool res = LuaWrapper::pcall(L, 0, 0);
|
||||
lua_close(L);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct AssetPlugin : AssetBrowser::IPlugin, AssetCompiler::IPlugin {
|
||||
explicit AssetPlugin(LuauAnalysis& analysis, StudioApp& app)
|
||||
|
@ -664,7 +718,23 @@ struct AssetPlugin : AssetBrowser::IPlugin, AssetCompiler::IPlugin {
|
|||
m_app.getAssetBrowser().addWindow(win.move());
|
||||
}
|
||||
|
||||
bool compile(const Path& src) override { return m_app.getAssetCompiler().copyCompile(src); }
|
||||
bool compile(const Path& src) override {
|
||||
FileSystem& fs = m_app.getEngine().getFileSystem();
|
||||
OutputMemoryStream src_data(m_app.getAllocator());
|
||||
if (!fs.getContentSync(src, src_data)) return false;
|
||||
|
||||
Array<Path> deps(m_app.getAllocator());
|
||||
if (!gatherRequires(src_data, deps)) return false;
|
||||
|
||||
OutputMemoryStream out(m_app.getAllocator());
|
||||
out.write(deps.size());
|
||||
for (const Path& dep : deps) {
|
||||
out.writeString(dep.c_str());
|
||||
}
|
||||
out.write(src_data.data(), src_data.size());
|
||||
return m_app.getAssetCompiler().writeCompiledResource(src, out);
|
||||
}
|
||||
|
||||
const char* getLabel() const override { return "Lua script"; }
|
||||
bool canCreateResource() const override { return true; }
|
||||
const char* getDefaultExtension() const override { return "lua"; }
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "engine/log.h"
|
||||
#include "engine/file_system.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/stream.h"
|
||||
#include "lua_script.h"
|
||||
|
||||
namespace Lumix {
|
||||
|
@ -10,15 +12,29 @@ LuaScript::LuaScript(const Path& path, ResourceManager& resource_manager, IAlloc
|
|||
: Resource(path, resource_manager, allocator)
|
||||
, m_allocator(allocator, m_path.c_str())
|
||||
, m_source_code(m_allocator)
|
||||
, m_dependencies(m_allocator)
|
||||
{
|
||||
}
|
||||
|
||||
LuaScript::~LuaScript() = default;
|
||||
|
||||
void LuaScript::unload() { m_source_code = ""; }
|
||||
void LuaScript::unload() {
|
||||
for (LuaScript* scr : m_dependencies) scr->decRefCount();
|
||||
m_dependencies.clear();
|
||||
m_source_code = "";
|
||||
}
|
||||
|
||||
bool LuaScript::load(Span<const u8> mem) {
|
||||
m_source_code = StringView((const char*)mem.begin(), mem.length());
|
||||
InputMemoryStream blob(mem.begin(), mem.length());
|
||||
u32 num_deps;
|
||||
blob.read(num_deps);
|
||||
for (u32 i = 0; i < num_deps; ++i) {
|
||||
const char* dep_path = blob.readString();
|
||||
LuaScript* scr = m_resource_manager.getOwner().load<LuaScript>(Path(dep_path));
|
||||
addDependency(*scr);
|
||||
m_dependencies.push(scr);
|
||||
}
|
||||
m_source_code = StringView((const char*)blob.skip(0), (u32)blob.remaining());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
|
||||
private:
|
||||
TagAllocator m_allocator;
|
||||
Array<LuaScript*> m_dependencies;
|
||||
String m_source_code;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "engine/world.h"
|
||||
#include "gui/gui_module.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include <luacode.h>
|
||||
|
||||
|
||||
namespace Lumix {
|
||||
|
@ -107,15 +108,6 @@ struct ArrayItemSetVisitor : reflection::IPropertyVisitor {
|
|||
lua_State* L;
|
||||
};
|
||||
|
||||
static void pushObject(lua_State* L, void* obj, StringView type_name) {
|
||||
ASSERT(!type_name.empty());
|
||||
const char* c = type_name.end - 1;
|
||||
while (*c != ':' && c != type_name.begin) --c;
|
||||
if (*c == ':') ++c;
|
||||
|
||||
LuaWrapper::pushObject(L, obj, StringView(c, u32(type_name.end - c - 2)));
|
||||
}
|
||||
|
||||
static void toVariant(reflection::Variant::Type type, lua_State* L, int idx, reflection::Variant& val) {
|
||||
switch(type) {
|
||||
case reflection::Variant::BOOL: val = LuaWrapper::checkArg<bool>(L, idx); break;
|
||||
|
@ -150,24 +142,57 @@ static void toVariant(reflection::Variant::Type type, lua_State* L, int idx, ref
|
|||
}
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const reflection::Variant& v, StringView type_name) {
|
||||
switch (v.type) {
|
||||
static bool isPath(const reflection::TypeDescriptor& type) {
|
||||
if (type.type != reflection::Variant::CSTR) return false;
|
||||
return equalStrings(type.type_name, "Path");
|
||||
}
|
||||
|
||||
static int push(lua_State* L, Span<u8> val, const reflection::TypeDescriptor& type, World* world) {
|
||||
#define RET(T) do { \
|
||||
T v; \
|
||||
ASSERT(sizeof(v) == val.length()); \
|
||||
memcpy(&v, val.m_begin, sizeof(v)); \
|
||||
LuaWrapper::push(L, v); \
|
||||
return 1; \
|
||||
} while(false) \
|
||||
|
||||
switch (type.type) {
|
||||
default:
|
||||
case reflection::Variant::ENTITY: ASSERT(false); return 0;
|
||||
case reflection::Variant::VOID: return 0;
|
||||
case reflection::Variant::BOOL: LuaWrapper::push(L, v.b); return 1;
|
||||
case reflection::Variant::U32: LuaWrapper::push(L, v.u); return 1;
|
||||
case reflection::Variant::I32: LuaWrapper::push(L, v.i); return 1;
|
||||
case reflection::Variant::FLOAT: LuaWrapper::push(L, v.f); return 1;
|
||||
case reflection::Variant::CSTR: LuaWrapper::push(L, v.s); return 1;
|
||||
case reflection::Variant::VEC2: LuaWrapper::push(L, v.v2); return 1;
|
||||
case reflection::Variant::BOOL: RET(bool);
|
||||
case reflection::Variant::U32: RET(u32);
|
||||
case reflection::Variant::I32: RET(i32);
|
||||
case reflection::Variant::VEC2: RET(Vec2);
|
||||
case reflection::Variant::COLOR:
|
||||
case reflection::Variant::VEC3: LuaWrapper::push(L, v.v3); return 1;
|
||||
case reflection::Variant::DVEC3: LuaWrapper::push(L, v.dv3); return 1;
|
||||
case reflection::Variant::QUAT: LuaWrapper::push(L, v.quat); return 1;
|
||||
case reflection::Variant::PTR: pushObject(L, v.ptr, type_name); return 1;
|
||||
case reflection::Variant::VEC3: RET(Vec3);
|
||||
case reflection::Variant::DVEC3: RET(DVec3);
|
||||
case reflection::Variant::QUAT: RET(Quat);
|
||||
case reflection::Variant::PTR: {
|
||||
if (type.is_pointer) {
|
||||
void* ptr;
|
||||
ASSERT(sizeof(ptr) == val.length());
|
||||
memcpy(&ptr, val.m_begin, sizeof(ptr));
|
||||
LuaWrapper::pushObject(L, ptr, type.type_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void* inst = type.create_copy(val.m_begin, getGlobalAllocator());
|
||||
LuaWrapper::pushObject(L, inst, type.type_name);
|
||||
return 1;
|
||||
}
|
||||
case reflection::Variant::FLOAT: RET(float);
|
||||
case reflection::Variant::CSTR: {
|
||||
if (isPath(type)) {
|
||||
LuaWrapper::push(L, (const char*)val.m_begin);
|
||||
return 1;
|
||||
}
|
||||
RET(const char*);
|
||||
}
|
||||
}
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
#undef RET
|
||||
}
|
||||
|
||||
static int luaMethodClosure(lua_State* L) {
|
||||
|
@ -189,8 +214,12 @@ static int luaMethodClosure(lua_State* L) {
|
|||
toVariant(type, L, i + 2, args[i]);
|
||||
}
|
||||
|
||||
const reflection::Variant res = f->invoke(obj, Span(args, f->getArgCount()));
|
||||
return push(L, res, f->getReturnTypeName());
|
||||
u8 res_mem[128];
|
||||
reflection::TypeDescriptor ret_type = f->getReturnType();
|
||||
ASSERT(ret_type.size <= sizeof(res_mem));
|
||||
Span<u8> res(res_mem, ret_type.size);
|
||||
f->invoke(obj, res, Span(args, f->getArgCount()));
|
||||
return push(L, res, f->getReturnType(), nullptr);
|
||||
}
|
||||
|
||||
static int luaModuleMethodClosure(lua_State* L) {
|
||||
|
@ -208,12 +237,14 @@ static int luaModuleMethodClosure(lua_State* L) {
|
|||
reflection::Variant::Type type = f->getArgType(i).type;
|
||||
toVariant(type, L, i + 2, args[i]);
|
||||
}
|
||||
const reflection::Variant res = f->invoke(module, Span(args, f->getArgCount()));
|
||||
if (res.type == reflection::Variant::ENTITY) {
|
||||
LuaWrapper::pushEntity(L, res.e, &module->getWorld());
|
||||
return 1;
|
||||
}
|
||||
return push(L, res, f->getReturnTypeName());
|
||||
|
||||
u8 res_mem[128];
|
||||
reflection::TypeDescriptor ret_type = f->getReturnType();
|
||||
ASSERT(ret_type.size <= sizeof(res_mem));
|
||||
Span<u8> res(res_mem, ret_type.size);
|
||||
|
||||
f->invoke(module, res, Span(args, f->getArgCount()));
|
||||
return push(L, res, f->getReturnType(), &module->getWorld());
|
||||
}
|
||||
|
||||
static int luaCmpMethodClosure(lua_State* L) {
|
||||
|
@ -242,12 +273,14 @@ static int luaCmpMethodClosure(lua_State* L) {
|
|||
reflection::Variant::Type type = f->getArgType(i).type;
|
||||
toVariant(type, L, i + 1, args[i]);
|
||||
}
|
||||
const reflection::Variant res = f->invoke(module, Span(args, f->getArgCount()));
|
||||
if (res.type == reflection::Variant::ENTITY) {
|
||||
LuaWrapper::pushEntity(L, res.e, &module->getWorld());
|
||||
return 1;
|
||||
}
|
||||
return push(L, res, f->getReturnTypeName());
|
||||
|
||||
u8 res_mem[sizeof(Path)];
|
||||
reflection::TypeDescriptor ret_type = f->getReturnType();
|
||||
ASSERT(ret_type.size <= sizeof(res_mem));
|
||||
Span<u8> res(res_mem, ret_type.size);
|
||||
|
||||
f->invoke(module, res, Span(args, f->getArgCount()));
|
||||
return push(L, res, f->getReturnType(), &module->getWorld());
|
||||
}
|
||||
|
||||
static int lua_struct_var_setter(lua_State* L) {
|
||||
|
@ -305,6 +338,10 @@ static int lua_struct_var_getter(lua_State* L) {
|
|||
LuaWrapper::push(L, var->get<DVec3>(inst));
|
||||
return 1;
|
||||
}
|
||||
case reflection::Variant::BOOL: {
|
||||
LuaWrapper::push(L, var->get<bool>(inst));
|
||||
return 1;
|
||||
}
|
||||
case reflection::Variant::VEC3: {
|
||||
LuaWrapper::push(L, var->get<Vec3>(inst));
|
||||
return 1;
|
||||
|
@ -313,6 +350,10 @@ static int lua_struct_var_getter(lua_State* L) {
|
|||
LuaWrapper::push(L, var->get<float>(inst));
|
||||
return 1;
|
||||
}
|
||||
case reflection::Variant::ENTITY: {
|
||||
LuaWrapper::push(L, var->get<EntityPtr>(inst).index);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
ASSERT(false);
|
||||
// TODO
|
||||
|
@ -374,12 +415,8 @@ static void createClasses(lua_State* L) {
|
|||
}
|
||||
|
||||
for (auto* f : reflection::allFunctions()) {
|
||||
char tmp_obj_type_name[128];
|
||||
copyString(Span(tmp_obj_type_name), f->getThisTypeName());
|
||||
const char* c = tmp_obj_type_name + strlen(tmp_obj_type_name);
|
||||
while (*c != ':' && c != tmp_obj_type_name) --c;
|
||||
if (*c == ':') ++c;
|
||||
const char* obj_type_name = c;
|
||||
char obj_type_name[128];
|
||||
copyString(Span(obj_type_name), f->getThisType().type_name);
|
||||
if (LuaWrapper::getField(L, -1, obj_type_name) != LUA_TTABLE) { // [LumixAPI, obj|nil ]
|
||||
lua_pop(L, 1); // [LumixAPI]
|
||||
lua_newtable(L); // [LumixAPI, obj]
|
||||
|
@ -1534,18 +1571,9 @@ public:
|
|||
|
||||
for (const reflection::FunctionBase* f : module->functions) {
|
||||
lua_pushlightuserdata(L, (void*)f); // [module, f]
|
||||
if (f->name) {
|
||||
lua_pushcclosure(L, luaModuleMethodClosure, f->name, 1);
|
||||
lua_setfield(L, -2, f->name); // [module]
|
||||
}
|
||||
else {
|
||||
const char* c = f->decl_code;
|
||||
while (*c != ':' && *c) ++c;
|
||||
ASSERT(*c == ':');
|
||||
c += 2;
|
||||
lua_pushcclosure(L, luaModuleMethodClosure, c, 1);
|
||||
lua_setfield(L, -2, c); // [module]
|
||||
}
|
||||
ASSERT(f->name);
|
||||
lua_pushcclosure(L, luaModuleMethodClosure, f->name, 1);
|
||||
lua_setfield(L, -2, f->name); // [module]
|
||||
}
|
||||
lua_pop(L, 1); // []
|
||||
|
||||
|
@ -2765,12 +2793,90 @@ struct LuaProperties : reflection::DynamicProperties {
|
|||
}
|
||||
};
|
||||
|
||||
static int finishrequire(lua_State* L)
|
||||
{
|
||||
if (lua_isstring(L, -1))
|
||||
lua_error(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int LUA_require(lua_State* L) {
|
||||
const char* name = luaL_checkstring(L, 1);
|
||||
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_MODULES", 1);
|
||||
|
||||
// return the module from the cache
|
||||
lua_getfield(L, -1, name);
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
// L stack: _MODULES result
|
||||
return finishrequire(L);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
Engine* engine = LuaWrapper::getClosureObject<Engine>(L);
|
||||
Path path(name, ".lua");
|
||||
LuaScript* dep = engine->getResourceManager().load<LuaScript>(path);
|
||||
if (!dep->isReady()) {
|
||||
ASSERT(false); // require-d modules should be registered as dependencies, so it should be impossible to get here
|
||||
luaL_argerrorL(L, 1, "error loading module");
|
||||
}
|
||||
|
||||
// module needs to run in a new thread, isolated from the rest
|
||||
// note: we create ML on main thread so that it doesn't inherit environment of L
|
||||
lua_State* GL = lua_mainthread(L);
|
||||
lua_State* ML = lua_newthread(GL);
|
||||
lua_xmove(GL, L, 1);
|
||||
|
||||
// new thread needs to have the globals sandboxed
|
||||
luaL_sandboxthread(ML);
|
||||
|
||||
// now we can compile & run module on the new thread
|
||||
size_t bytecode_size;
|
||||
char* bytecode = luau_compile((const char*)dep->getSourceCode().begin, dep->getSourceCode().size(), nullptr, &bytecode_size);
|
||||
if (luau_load(ML, name, bytecode, bytecode_size, 0) == 0)
|
||||
{
|
||||
int status = lua_resume(ML, L, 0);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
if (lua_gettop(ML) == 0)
|
||||
lua_pushstring(ML, "module must return a value");
|
||||
else if (!lua_istable(ML, -1) && !lua_isfunction(ML, -1))
|
||||
lua_pushstring(ML, "module must return a table or function");
|
||||
}
|
||||
else if (status == LUA_YIELD)
|
||||
{
|
||||
lua_pushstring(ML, "module can not yield");
|
||||
}
|
||||
else if (!lua_isstring(ML, -1))
|
||||
{
|
||||
lua_pushstring(ML, "unknown error while running module");
|
||||
}
|
||||
}
|
||||
free(bytecode);
|
||||
|
||||
// there's now a return value on top of ML; L stack: _MODULES ML
|
||||
lua_xmove(ML, L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -4, name);
|
||||
|
||||
// L stack: _MODULES ML result
|
||||
return finishrequire(L);
|
||||
}
|
||||
|
||||
LuaScriptSystemImpl::LuaScriptSystemImpl(Engine& engine)
|
||||
: m_engine(engine)
|
||||
, m_allocator(engine.getAllocator(), "lua system")
|
||||
, m_script_manager(m_allocator)
|
||||
{
|
||||
lua_State* L = engine.getState();
|
||||
lua_pushlightuserdata(L, &engine);
|
||||
lua_pushcclosure(L, &LUA_require, "require", 1);
|
||||
lua_setglobal(L, "require");
|
||||
|
||||
m_script_manager.create(LuaScript::TYPE, engine.getResourceManager());
|
||||
|
||||
LUMIX_MODULE(LuaScriptModuleImpl, "lua_script")
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "engine/resource_manager.h"
|
||||
#include "engine/world.h"
|
||||
#include "gui/gui_system.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "renderer/gpu/gpu.h"
|
||||
#include "renderer/pipeline.h"
|
||||
#include "renderer/render_module.h"
|
||||
|
@ -68,7 +69,7 @@ void GameView::init() {
|
|||
|
||||
Engine& engine = m_app.getEngine();
|
||||
auto* renderer = (Renderer*)engine.getSystemManager().getSystem("renderer");
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = engine.getResourceManager().load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_pipeline = Pipeline::create(*renderer, pres, "GAME_VIEW");
|
||||
|
||||
auto* gui = static_cast<GUISystem*>(engine.getSystemManager().getSystem("gui"));
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "engine/world.h"
|
||||
#include "fbx_importer.h"
|
||||
#include "game_view.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "model_meta.h"
|
||||
#include "renderer/culling_system.h"
|
||||
#include "renderer/editor/composite_texture.h"
|
||||
|
@ -659,80 +660,6 @@ struct FontPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
|
|||
};
|
||||
|
||||
|
||||
struct PipelinePlugin final : AssetCompiler::IPlugin, AssetBrowser::IPlugin {
|
||||
struct EditorWindow : AssetEditorWindow {
|
||||
EditorWindow(const Path& path, StudioApp& app, IAllocator& allocator)
|
||||
: AssetEditorWindow(app)
|
||||
, m_app(app)
|
||||
{
|
||||
m_resource = app.getEngine().getResourceManager().load<PipelineResource>(path);
|
||||
}
|
||||
|
||||
~EditorWindow() {
|
||||
m_resource->decRefCount();
|
||||
}
|
||||
|
||||
void save() {
|
||||
OutputMemoryStream blob(m_app.getAllocator());
|
||||
m_editor->serializeText(blob);
|
||||
m_app.getAssetBrowser().saveResource(m_resource->getPath(), blob);
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
bool onAction(const Action& action) override {
|
||||
if (&action == &m_app.getCommonActions().save) save();
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void windowGUI() override {
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGuiEx::IconButton(ICON_FA_SAVE, "Save")) save();
|
||||
if (ImGuiEx::IconButton(ICON_FA_EXTERNAL_LINK_ALT, "Open externally")) m_app.getAssetBrowser().openInExternalEditor(m_resource);
|
||||
if (ImGuiEx::IconButton(ICON_FA_SEARCH, "View in browser")) m_app.getAssetBrowser().locate(*m_resource);
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
if (m_resource->isEmpty()) {
|
||||
ImGui::TextUnformatted("Loading...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_editor) {
|
||||
m_editor = createLuaCodeEditor(m_app);
|
||||
m_editor->setText(m_resource->content);
|
||||
}
|
||||
|
||||
ImGui::PushFont(m_app.getMonospaceFont());
|
||||
if (m_editor->gui("codeeditor")) m_dirty = true;
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
const Path& getPath() override { return m_resource->getPath(); }
|
||||
const char* getName() const override { return "pipeline editor"; }
|
||||
|
||||
StudioApp& m_app;
|
||||
PipelineResource* m_resource;
|
||||
UniquePtr<CodeEditor> m_editor;
|
||||
};
|
||||
|
||||
explicit PipelinePlugin(StudioApp& app)
|
||||
: m_app(app)
|
||||
{}
|
||||
|
||||
bool compile(const Path& src) override { return m_app.getAssetCompiler().copyCompile(src); }
|
||||
const char* getLabel() const override { return "Pipeline"; }
|
||||
|
||||
void openEditor(const struct Path& path) override {
|
||||
IAllocator& allocator = m_app.getAllocator();
|
||||
UniquePtr<EditorWindow> win = UniquePtr<EditorWindow>::create(allocator, path, m_app, m_app.getAllocator());
|
||||
m_app.getAssetBrowser().addWindow(win.move());
|
||||
}
|
||||
|
||||
StudioApp& m_app;
|
||||
};
|
||||
|
||||
|
||||
struct ParticleSystemPropertyPlugin final : PropertyGrid::IPlugin
|
||||
{
|
||||
ParticleSystemPropertyPlugin(StudioApp& app) : m_app(app) {}
|
||||
|
@ -2707,7 +2634,7 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin {
|
|||
{
|
||||
Engine& engine = m_app.getEngine();
|
||||
m_tile.world = &engine.createWorld(false);
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = engine.getResourceManager().load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_tile.pipeline = Pipeline::create(*m_renderer, pres, "PREVIEW");
|
||||
|
||||
RenderModule* render_module = (RenderModule*)m_tile.world->getModule(MODEL_INSTANCE_TYPE);
|
||||
|
@ -3525,7 +3452,7 @@ struct EnvironmentProbePlugin final : PropertyGrid::IPlugin
|
|||
SystemManager& system_manager = engine.getSystemManager();
|
||||
Renderer* renderer = static_cast<Renderer*>(system_manager.getSystem("renderer"));
|
||||
ResourceManagerHub& rm = engine.getResourceManager();
|
||||
PipelineResource* pres = rm.load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = rm.load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_pipeline = Pipeline::create(*renderer, pres, "PROBE");
|
||||
m_ibl_filter_shader = rm.load<Shader>(Path("pipelines/ibl_filter.shd"));
|
||||
}
|
||||
|
@ -4110,10 +4037,8 @@ struct InstancedModelPlugin final : PropertyGrid::IPlugin, StudioApp::MousePlugi
|
|||
if (!cmp.im->model || !cmp.im->model->isReady()) return false;
|
||||
|
||||
WorldEditor& editor = m_app.getWorldEditor();
|
||||
DVec3 ray_origin;
|
||||
Vec3 ray_dir;
|
||||
editor.getView().getViewport().getRay(Vec2((float)x, (float)y), ray_origin, ray_dir);
|
||||
const RayCastModelHit hit = m_brush != Brush::TERRAIN ? cmp.module->castRay(ray_origin, ray_dir, INVALID_ENTITY) : cmp.module->castRayTerrain(ray_origin, ray_dir);
|
||||
const Ray ray = editor.getView().getViewport().getRay(Vec2((float)x, (float)y));
|
||||
const RayCastModelHit hit = m_brush != Brush::TERRAIN ? cmp.module->castRay(ray, INVALID_ENTITY) : cmp.module->castRayTerrain(ray);
|
||||
if (!hit.is_hit) return false;
|
||||
|
||||
const DVec3 hit_pos = hit.origin + hit.t * hit.dir;
|
||||
|
@ -4231,10 +4156,8 @@ struct InstancedModelPlugin final : PropertyGrid::IPlugin, StudioApp::MousePlugi
|
|||
if (!cmp.im) return false;
|
||||
if (!cmp.im->model || !cmp.im->model->isReady()) return false;
|
||||
|
||||
DVec3 ray_origin;
|
||||
Vec3 ray_dir;
|
||||
view.getViewport().getRay(Vec2((float)x, (float)y), ray_origin, ray_dir);
|
||||
RayCastModelHit hit = cmp.module->castRayInstancedModels(ray_origin, ray_dir, [](const RayCastModelHit&){ return true; });
|
||||
const Ray ray = view.getViewport().getRay(Vec2((float)x, (float)y));
|
||||
RayCastModelHit hit = cmp.module->castRayInstancedModels(ray, [](const RayCastModelHit&){ return true; });
|
||||
if (hit.is_hit && hit.entity == cmp.entity) {
|
||||
m_selected = cmp.module->getInstancedModels()[cmp.entity].instances[hit.subindex];
|
||||
return true;
|
||||
|
@ -4389,10 +4312,8 @@ struct InstancedModelPlugin final : PropertyGrid::IPlugin, StudioApp::MousePlugi
|
|||
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
const Vec2 mp = editor.getView().getMousePos();
|
||||
DVec3 ray_origin;
|
||||
Vec3 ray_dir;
|
||||
editor.getView().getViewport().getRay(mp, ray_origin, ray_dir);
|
||||
const RayCastModelHit hit = render_module->castRayTerrain(ray_origin, ray_dir);
|
||||
const Ray ray = editor.getView().getViewport().getRay(mp);
|
||||
const RayCastModelHit hit = render_module->castRayTerrain(ray);
|
||||
if (hit.is_hit) {
|
||||
drawCircle(*render_module, hit.origin + hit.t * hit.dir, m_brush_radius, 0xff880000);
|
||||
}
|
||||
|
@ -4485,10 +4406,8 @@ struct ProceduralGeomPlugin final : PropertyGrid::IPlugin, StudioApp::MousePlugi
|
|||
RenderModule* module = (RenderModule*)world.getModule("renderer");
|
||||
if (!world.hasComponent(entity, PROCEDURAL_GEOM_TYPE)) return false;
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
view.getViewport().getRay({(float)x, (float)y}, origin, dir);
|
||||
const RayCastModelHit hit = module->castRay(origin, dir, [entity](const RayCastModelHit& hit) {
|
||||
const Ray ray = view.getViewport().getRay({(float)x, (float)y});
|
||||
const RayCastModelHit hit = module->castRay(ray, [entity](const RayCastModelHit& hit) {
|
||||
return hit.entity == entity;
|
||||
});
|
||||
if (!hit.is_hit) return false;
|
||||
|
@ -4510,10 +4429,8 @@ struct ProceduralGeomPlugin final : PropertyGrid::IPlugin, StudioApp::MousePlugi
|
|||
World& world = *editor.getWorld();
|
||||
|
||||
RenderModule* module = static_cast<RenderModule*>(world.getModule("renderer"));
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
view.getViewport().getRay(mp, origin, dir);
|
||||
const RayCastModelHit hit = module->castRay(origin, dir, [entity](const RayCastModelHit& hit){
|
||||
const Ray ray = view.getViewport().getRay(mp);
|
||||
const RayCastModelHit hit = module->castRay(ray, [entity](const RayCastModelHit& hit){
|
||||
return hit.entity == entity;
|
||||
});
|
||||
|
||||
|
@ -4824,10 +4741,10 @@ struct RenderInterfaceImpl final : RenderInterface
|
|||
}
|
||||
|
||||
|
||||
WorldView::RayHit castRay(World& world, const DVec3& origin, const Vec3& dir, EntityPtr ignored) override
|
||||
WorldView::RayHit castRay(World& world, const Ray& ray, EntityPtr ignored) override
|
||||
{
|
||||
RenderModule* module = (RenderModule*)world.getModule(ENVIRONMENT_PROBE_TYPE);
|
||||
const RayCastModelHit hit = module->castRay(origin, dir, ignored);
|
||||
const RayCastModelHit hit = module->castRay(ray, ignored);
|
||||
|
||||
return {hit.is_hit, hit.t, hit.entity, hit.origin + hit.dir * hit.t};
|
||||
}
|
||||
|
@ -5233,7 +5150,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
{
|
||||
StudioAppPlugin(StudioApp& app)
|
||||
: m_app(app)
|
||||
, m_pipeline_plugin(app)
|
||||
, m_font_plugin(app)
|
||||
, m_material_plugin(app)
|
||||
, m_particle_emitter_property_plugin(app)
|
||||
|
@ -5293,9 +5209,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
const char* texture_exts[] = {"png", "jpg", "jpeg", "tga", "raw", "ltc"};
|
||||
asset_compiler.addPlugin(m_texture_plugin, Span(texture_exts));
|
||||
|
||||
const char* pipeline_exts[] = {"pln"};
|
||||
asset_compiler.addPlugin(m_pipeline_plugin, Span(pipeline_exts));
|
||||
|
||||
const char* material_exts[] = {"mat"};
|
||||
asset_compiler.addPlugin(m_material_plugin, Span(material_exts));
|
||||
|
||||
|
@ -5313,7 +5226,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
asset_browser.addPlugin(m_shader_plugin, Span(shader_exts));
|
||||
asset_browser.addPlugin(m_shader_include_plugin, Span(inc_exts));
|
||||
asset_browser.addPlugin(m_texture_plugin, Span(texture_exts));
|
||||
asset_browser.addPlugin(m_pipeline_plugin, Span(pipeline_exts));
|
||||
|
||||
m_app.addPlugin(m_scene_view);
|
||||
m_app.addPlugin(m_game_view);
|
||||
|
@ -5532,7 +5444,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
asset_browser.removePlugin(m_texture_plugin);
|
||||
asset_browser.removePlugin(m_shader_plugin);
|
||||
asset_browser.removePlugin(m_shader_include_plugin);
|
||||
asset_browser.removePlugin(m_pipeline_plugin);
|
||||
|
||||
AssetCompiler& asset_compiler = m_app.getAssetCompiler();
|
||||
asset_compiler.removePlugin(m_font_plugin);
|
||||
|
@ -5541,7 +5452,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
asset_compiler.removePlugin(m_texture_plugin);
|
||||
asset_compiler.removePlugin(m_model_plugin);
|
||||
asset_compiler.removePlugin(m_material_plugin);
|
||||
asset_compiler.removePlugin(m_pipeline_plugin);
|
||||
|
||||
m_app.removePlugin(m_scene_view);
|
||||
m_app.removePlugin(m_game_view);
|
||||
|
@ -5565,7 +5475,6 @@ struct StudioAppPlugin : StudioApp::IPlugin
|
|||
EditorUIRenderPlugin m_editor_ui_render_plugin;
|
||||
MaterialPlugin m_material_plugin;
|
||||
ParticleSystemPropertyPlugin m_particle_emitter_property_plugin;
|
||||
PipelinePlugin m_pipeline_plugin;
|
||||
FontPlugin m_font_plugin;
|
||||
ShaderIncludePlugin m_shader_include_plugin;
|
||||
ShaderPlugin m_shader_plugin;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "engine/resource_manager.h"
|
||||
#include "engine/string.h"
|
||||
#include "engine/world.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "renderer/culling_system.h"
|
||||
#include "renderer/draw2d.h"
|
||||
#include "renderer/font.h"
|
||||
|
@ -122,10 +123,8 @@ struct WorldViewImpl final : WorldView {
|
|||
{
|
||||
if (m_snap_mode != SnapMode::VERTEX) return;
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
m_viewport.getRay(m_mouse_pos, origin, dir);
|
||||
const RayCastModelHit hit = m_module->castRay(origin, dir, INVALID_ENTITY);
|
||||
const Ray ray = m_viewport.getRay(m_mouse_pos);
|
||||
const RayCastModelHit hit = m_module->castRay(ray, INVALID_ENTITY);
|
||||
if (!hit.is_hit) return;
|
||||
|
||||
const DVec3 snap_pos = getClosestVertex(hit);
|
||||
|
@ -183,15 +182,13 @@ struct WorldViewImpl final : WorldView {
|
|||
}
|
||||
else
|
||||
{
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
m_viewport.getRay(m_mouse_pos, origin, dir);
|
||||
const RayCastModelHit hit = m_module->castRay(origin, dir, INVALID_ENTITY);
|
||||
const Ray ray = m_viewport.getRay(m_mouse_pos);
|
||||
const RayCastModelHit hit = m_module->castRay(ray, INVALID_ENTITY);
|
||||
|
||||
const Array<EntityRef>& selected_entities = m_editor.getSelectedEntities();
|
||||
if (m_snap_mode != SnapMode::NONE && !selected_entities.empty() && hit.is_hit)
|
||||
{
|
||||
DVec3 snap_pos = origin + dir * hit.t;
|
||||
DVec3 snap_pos = ray.origin + ray.dir * hit.t;
|
||||
if (m_snap_mode == SnapMode::VERTEX) snap_pos = getClosestVertex(hit);
|
||||
const Quat rot = m_editor.getWorld()->getRotation(selected_entities[0]);
|
||||
const Gizmo::Config& gizmo_cfg = m_app.getGizmoConfig();
|
||||
|
@ -200,7 +197,7 @@ struct WorldViewImpl final : WorldView {
|
|||
}
|
||||
else
|
||||
{
|
||||
auto icon_hit = m_icons->raycast(origin, dir);
|
||||
auto icon_hit = m_icons->raycast(ray.origin, ray.dir);
|
||||
if (icon_hit.entity != INVALID_ENTITY) {
|
||||
if(icon_hit.entity.isValid()) {
|
||||
EntityRef e = (EntityRef)icon_hit.entity;
|
||||
|
@ -239,10 +236,8 @@ struct WorldViewImpl final : WorldView {
|
|||
const Array<EntityRef>& selected_entities = m_editor.getSelectedEntities();
|
||||
if (selected_entities.empty()) return;
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
m_viewport.getRay(m_mouse_pos, origin, dir);
|
||||
const RayCastModelHit hit = m_module->castRay(origin, dir, INVALID_ENTITY);
|
||||
const Ray ray = m_viewport.getRay(m_mouse_pos);
|
||||
const RayCastModelHit hit = m_module->castRay(ray, INVALID_ENTITY);
|
||||
if (!hit.is_hit || hit.entity != selected_entities[0]) return;
|
||||
|
||||
const DVec3 snap_pos = getClosestVertex(hit);
|
||||
|
@ -351,10 +346,8 @@ struct WorldViewImpl final : WorldView {
|
|||
}
|
||||
else if (button == os::MouseButton::LEFT)
|
||||
{
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
m_viewport.getRay({(float)x, (float)y}, origin, dir);
|
||||
const RayCastModelHit hit = m_module->castRay(origin, dir, INVALID_ENTITY);
|
||||
const Ray ray = m_viewport.getRay({(float)x, (float)y});
|
||||
const RayCastModelHit hit = m_module->castRay(ray, INVALID_ENTITY);
|
||||
if (Gizmo::isActive()) return;
|
||||
|
||||
if (m_scene_view.m_is_measure_active) {
|
||||
|
@ -537,13 +530,11 @@ struct WorldViewImpl final : WorldView {
|
|||
RayHit res;
|
||||
const Vec2 center{float(cam_x), float(cam_y)};
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
m_viewport.getRay(center, origin, dir);
|
||||
const RayCastModelHit hit = m_module->castRay(origin, dir, ignore);
|
||||
const Ray ray = m_viewport.getRay(center);
|
||||
const RayCastModelHit hit = m_module->castRay(ray, ignore);
|
||||
DVec3 pos;
|
||||
if (hit.is_hit) {
|
||||
res.pos = origin + dir * hit.t;
|
||||
res.pos = ray.origin + ray.dir * hit.t;
|
||||
res.t = hit.t;
|
||||
res.entity = hit.entity;
|
||||
res.is_hit = true;
|
||||
|
@ -675,10 +666,6 @@ SceneView::SceneView(StudioApp& app)
|
|||
m_app.addAction(&m_move_entity_S_action);
|
||||
m_app.addAction(&m_move_entity_W_action);
|
||||
m_app.addAction(&m_toggle_projection_action);
|
||||
|
||||
const ResourceType pipeline_type("pipeline");
|
||||
m_app.getAssetCompiler().registerExtension("pln", pipeline_type);
|
||||
|
||||
}
|
||||
|
||||
void SceneView::toggleProjection() {
|
||||
|
@ -693,7 +680,7 @@ void SceneView::init() {
|
|||
|
||||
Engine& engine = m_app.getEngine();
|
||||
auto* renderer = static_cast<Renderer*>(engine.getSystemManager().getSystem("renderer"));
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = engine.getResourceManager().load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_pipeline = Pipeline::create(*renderer, pres, "SCENE_VIEW");
|
||||
m_pipeline->addCustomCommandHandler("renderSelection").callback.bind<&SceneView::renderSelection>(this);
|
||||
m_pipeline->addCustomCommandHandler("renderGizmos").callback.bind<&SceneView::renderGizmos>(this);
|
||||
|
@ -1098,10 +1085,8 @@ RayCastModelHit SceneView::castRay(float x, float y)
|
|||
ASSERT(module);
|
||||
|
||||
const Viewport& vp = m_view->getViewport();
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
vp.getRay({x * vp.w, y * vp.h}, origin, dir);
|
||||
return module->castRay(origin, dir, INVALID_ENTITY);
|
||||
const Ray ray = vp.getRay({x * vp.w, y * vp.h});
|
||||
return module->castRay(ray, INVALID_ENTITY);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -915,10 +915,8 @@ bool TerrainEditor::onMouseDown(WorldView& view, int x, int y)
|
|||
if (!is_terrain) return false;
|
||||
|
||||
RenderModule* module = (RenderModule*)world.getModule(TERRAIN_TYPE);
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
view.getViewport().getRay({(float)x, (float)y}, origin, dir);
|
||||
const RayCastModelHit hit = module->castRayTerrain(origin, dir);
|
||||
const Ray ray = view.getViewport().getRay({(float)x, (float)y});
|
||||
const RayCastModelHit hit = module->castRayTerrain(ray);
|
||||
if (!hit.is_hit) return false;
|
||||
|
||||
const DVec3 hit_pos = hit.origin + hit.dir * hit.t;
|
||||
|
@ -1184,11 +1182,9 @@ void TerrainEditor::onMouseMove(WorldView& view, int x, int y, int, int)
|
|||
World& world = *editor.getWorld();
|
||||
if (!world.hasComponent(entity, TERRAIN_TYPE)) return;
|
||||
RenderModule* module = (RenderModule*)world.getModule(TERRAIN_TYPE);
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
view.getViewport().getRay({(float)x, (float)y}, origin, dir);
|
||||
const Ray ray = view.getViewport().getRay({(float)x, (float)y});
|
||||
|
||||
const RayCastModelHit hit = module->castRayTerrain(origin, dir);
|
||||
const RayCastModelHit hit = module->castRayTerrain(ray);
|
||||
if (!hit.is_hit) return;
|
||||
if (hit.entity != entity) return;
|
||||
|
||||
|
@ -2038,10 +2034,8 @@ void TerrainEditor::onGUI(ComponentUID cmp, WorldEditor& editor) {
|
|||
for(auto entity : editor.getSelectedEntities()) {
|
||||
if (!world.hasComponent(entity, TERRAIN_TYPE)) continue;
|
||||
|
||||
DVec3 origin;
|
||||
Vec3 dir;
|
||||
editor.getView().getViewport().getRay(mp, origin, dir);
|
||||
const RayCastModelHit hit = module->castRayTerrain(origin, dir);
|
||||
const Ray ray = editor.getView().getViewport().getRay(mp);
|
||||
const RayCastModelHit hit = module->castRayTerrain(ray);
|
||||
|
||||
if(hit.is_hit) {
|
||||
DVec3 center = hit.origin + hit.dir * hit.t;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "editor/studio_app.h"
|
||||
#include "editor/settings.h"
|
||||
#include "editor/utils.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "renderer/model.h"
|
||||
#include "renderer/pose.h"
|
||||
#include "renderer/render_module.h"
|
||||
|
@ -31,7 +32,7 @@ WorldViewer::WorldViewer(StudioApp& app)
|
|||
m_viewport.rot = Quat::IDENTITY;
|
||||
|
||||
m_world = &engine.createWorld(false);
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
LuaScript* pres = engine.getResourceManager().load<LuaScript>(Path("pipelines/main.lua"));
|
||||
m_pipeline = Pipeline::create(*renderer, pres, "PREVIEW");
|
||||
|
||||
const EntityRef mesh_entity = m_world->createEntity({0, 0, 0}, {0, 0, 0, 1});
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "engine/resource_manager.h"
|
||||
#include "engine/stack_array.h"
|
||||
#include "engine/world.h"
|
||||
#include "lua_script/lua_script.h"
|
||||
#include "culling_system.h"
|
||||
#include "draw2d.h"
|
||||
#include "draw_stream.h"
|
||||
|
@ -356,31 +357,9 @@ struct ShadowAtlas {
|
|||
EntityPtr inv_map[64];
|
||||
};
|
||||
|
||||
|
||||
static const float SHADOW_CAM_FAR = 500.0f;
|
||||
|
||||
|
||||
ResourceType PipelineResource::TYPE("pipeline");
|
||||
|
||||
|
||||
void PipelineResource::unload()
|
||||
{
|
||||
content.resize(0);
|
||||
}
|
||||
|
||||
|
||||
bool PipelineResource::load(Span<const u8> mem) {
|
||||
content = StringView((const char*)mem.begin(), mem.length());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PipelineResource::PipelineResource(const Path& path, ResourceManager& owner, Renderer&, IAllocator& allocator)
|
||||
: Resource(path, owner, allocator)
|
||||
, content(allocator)
|
||||
{}
|
||||
|
||||
|
||||
struct PipelineImpl final : Pipeline
|
||||
{
|
||||
using RenderbufferDescHandle = u32;
|
||||
|
@ -689,7 +668,7 @@ struct PipelineImpl final : Pipeline
|
|||
}
|
||||
|
||||
|
||||
PipelineImpl(Renderer& renderer, PipelineResource* resource, const char* define, IAllocator& allocator)
|
||||
PipelineImpl(Renderer& renderer, LuaScript* resource, const char* define, IAllocator& allocator)
|
||||
: m_allocator(allocator)
|
||||
, m_renderer(renderer)
|
||||
, m_resource(resource)
|
||||
|
@ -931,10 +910,8 @@ struct PipelineImpl final : Pipeline
|
|||
|
||||
setDefine();
|
||||
|
||||
const char* content = m_resource->content.c_str();
|
||||
const int content_size = m_resource->content.length();
|
||||
bool errors =
|
||||
LuaWrapper::luaL_loadbuffer(m_lua_state, content, content_size, m_resource->getPath().c_str()) != 0;
|
||||
StringView content = m_resource->getSourceCode();
|
||||
bool errors = LuaWrapper::luaL_loadbuffer(m_lua_state, content.begin, content.size(), m_resource->getPath().c_str()) != 0;
|
||||
if (errors)
|
||||
{
|
||||
logError(m_resource->getPath(), ": ", lua_tostring(m_lua_state, -1));
|
||||
|
@ -3075,6 +3052,7 @@ struct PipelineImpl final : Pipeline
|
|||
|
||||
void fillClusters(DrawStream& stream, const CameraParams& cp) {
|
||||
PROFILE_FUNCTION();
|
||||
ASSERT(cp.frustum.xs[0] == cp.frustum.xs[0]);
|
||||
ASSERT(cp.pos.x == cp.pos.x);
|
||||
struct ClusterLight {
|
||||
Vec3 pos;
|
||||
|
@ -4076,7 +4054,7 @@ struct PipelineImpl final : Pipeline
|
|||
|
||||
IAllocator& m_allocator;
|
||||
Renderer& m_renderer;
|
||||
PipelineResource* m_resource;
|
||||
LuaScript* m_resource;
|
||||
lua_State* m_lua_state;
|
||||
int m_lua_thread_ref;
|
||||
int m_lua_env;
|
||||
|
@ -4132,7 +4110,7 @@ struct PipelineImpl final : Pipeline
|
|||
};
|
||||
|
||||
|
||||
UniquePtr<Pipeline> Pipeline::create(Renderer& renderer, PipelineResource* resource, const char* define)
|
||||
UniquePtr<Pipeline> Pipeline::create(Renderer& renderer, LuaScript* resource, const char* define)
|
||||
{
|
||||
return UniquePtr<PipelineImpl>::create(renderer.getAllocator(), renderer, resource, define, renderer.getAllocator());
|
||||
}
|
||||
|
|
|
@ -44,18 +44,6 @@ namespace UniformBuffer {
|
|||
};
|
||||
}
|
||||
|
||||
struct LUMIX_RENDERER_API PipelineResource : Resource {
|
||||
static ResourceType TYPE;
|
||||
|
||||
PipelineResource(const Path& path, ResourceManager& owner, Renderer& renderer, IAllocator& allocator);
|
||||
|
||||
void unload() override;
|
||||
bool load(Span<const u8> mem) override;
|
||||
ResourceType getType() const override { return TYPE; }
|
||||
|
||||
String content;
|
||||
};
|
||||
|
||||
|
||||
struct LUMIX_RENDERER_API Pipeline {
|
||||
struct CustomCommandHandler {
|
||||
|
@ -64,7 +52,7 @@ struct LUMIX_RENDERER_API Pipeline {
|
|||
RuntimeHash hash;
|
||||
};
|
||||
|
||||
static UniquePtr<Pipeline> create(Renderer& renderer, PipelineResource* resource, const char* define);
|
||||
static UniquePtr<Pipeline> create(Renderer& renderer, struct LuaScript* resource, const char* define);
|
||||
|
||||
virtual ~Pipeline() {}
|
||||
|
||||
|
|
|
@ -2026,7 +2026,7 @@ struct RenderModuleImpl final : RenderModule {
|
|||
|
||||
const Ray ray = module->getCameraRay(camera_entity, {x, y});
|
||||
|
||||
RayCastModelHit hit = module->castRay(ray.origin, ray.dir, INVALID_ENTITY);
|
||||
RayCastModelHit hit = module->castRay(ray, INVALID_ENTITY);
|
||||
LuaWrapper::push(L, hit.is_hit);
|
||||
LuaWrapper::push(L, hit.is_hit ? hit.origin + hit.dir * hit.t : DVec3(0));
|
||||
LuaWrapper::pushEntity(L, hit.is_hit ? hit.entity : INVALID_ENTITY, &module->getWorld());
|
||||
|
@ -2518,12 +2518,12 @@ struct RenderModuleImpl final : RenderModule {
|
|||
}
|
||||
|
||||
|
||||
RayCastModelHit castRayTerrain(const DVec3& origin, const Vec3& dir) override
|
||||
RayCastModelHit castRayTerrain(const Ray& ray) override
|
||||
{
|
||||
RayCastModelHit hit;
|
||||
hit.is_hit = false;
|
||||
for (Terrain* terrain : m_terrains) {
|
||||
hit = terrain->castRay(origin, dir);
|
||||
hit = terrain->castRay(ray);
|
||||
hit.component_type = TERRAIN_TYPE;
|
||||
hit.entity = terrain->getEntity();
|
||||
if (hit.is_hit) break;
|
||||
|
@ -2531,13 +2531,13 @@ struct RenderModuleImpl final : RenderModule {
|
|||
return hit;
|
||||
}
|
||||
|
||||
RayCastModelHit castRay(const DVec3& origin, const Vec3& dir, EntityPtr ignored_model_instance) override {
|
||||
return castRay(origin, dir, [&](const RayCastModelHit& hit) -> bool {
|
||||
RayCastModelHit castRay(const Ray& ray, EntityPtr ignored_model_instance) override {
|
||||
return castRay(ray, [&](const RayCastModelHit& hit) -> bool {
|
||||
return hit.entity != ignored_model_instance || !ignored_model_instance.isValid();
|
||||
});
|
||||
}
|
||||
|
||||
RayCastModelHit castRayInstancedModels(const DVec3& ray_origin, const Vec3& ray_dir, const RayCastModelHit::Filter& filter) override {
|
||||
RayCastModelHit castRayInstancedModels(const Ray& ray, const RayCastModelHit::Filter& filter) override {
|
||||
RayCastModelHit hit;
|
||||
hit.is_hit = false;
|
||||
for (auto iter = m_instanced_models.begin(), end = m_instanced_models.end(); iter != end; ++iter) {
|
||||
|
@ -2556,12 +2556,12 @@ struct RenderModuleImpl final : RenderModule {
|
|||
return res;
|
||||
};
|
||||
for (const InstancedModel::InstanceData& id : im.instances) {
|
||||
Vec3 rel_pos = Vec3(ray_origin - tr.pos) - id.pos;
|
||||
Vec3 rel_pos = Vec3(ray.origin - tr.pos) - id.pos;
|
||||
const float radius = model_radius * id.scale;
|
||||
float intersection_t;
|
||||
if (getRaySphereIntersection(rel_pos, ray_dir, Vec3::ZERO, radius, intersection_t) && intersection_t >= 0) {
|
||||
if (getRaySphereIntersection(rel_pos, ray.dir, Vec3::ZERO, radius, intersection_t) && intersection_t >= 0) {
|
||||
const Quat rot = getInstanceQuat(id.rot_quat);
|
||||
const Vec3 rel_dir = rot.conjugated().rotate(ray_dir);
|
||||
const Vec3 rel_dir = rot.conjugated().rotate(ray.dir);
|
||||
rel_pos = rot.conjugated().rotate(rel_pos / id.scale);
|
||||
RayCastModelHit new_hit = im.model->castRay(rel_pos, rel_dir, nullptr, e, &filter);
|
||||
if (new_hit.is_hit && (!hit.is_hit || new_hit.t * id.scale < hit.t)) {
|
||||
|
@ -2578,7 +2578,7 @@ struct RenderModuleImpl final : RenderModule {
|
|||
return hit;
|
||||
}
|
||||
|
||||
RayCastModelHit castRayProceduralGeometry(const DVec3& origin, const Vec3& dir, const RayCastModelHit::Filter& filter) {
|
||||
RayCastModelHit castRayProceduralGeometry(const Ray& ray, const RayCastModelHit::Filter& filter) {
|
||||
RayCastModelHit hit;
|
||||
hit.is_hit = false;
|
||||
for (auto iter = m_procedural_geometries.begin(), end = m_procedural_geometries.end(); iter != end; ++iter) {
|
||||
|
@ -2593,8 +2593,8 @@ struct RenderModuleImpl final : RenderModule {
|
|||
|
||||
const DVec3& pos = m_world.getPosition(iter.key());
|
||||
const Quat rot = m_world.getRotation(iter.key()).conjugated();
|
||||
const Vec3 rd = rot.rotate(dir);
|
||||
Vec3 ro = Vec3(origin - pos);
|
||||
const Vec3 rd = rot.rotate(ray.dir);
|
||||
Vec3 ro = Vec3(ray.origin - pos);
|
||||
|
||||
Vec3 dummy;
|
||||
if (!pg.aabb.contains(ro) && !getRayAABBIntersection(ro, rd, pg.aabb.min, pg.aabb.max - pg.aabb.min, dummy)) continue;
|
||||
|
@ -2637,17 +2637,16 @@ struct RenderModuleImpl final : RenderModule {
|
|||
}
|
||||
}
|
||||
}
|
||||
hit.origin = origin;
|
||||
hit.dir = dir;
|
||||
hit.origin = ray.origin;
|
||||
hit.dir = ray.dir;
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
||||
RayCastModelHit castRay(const DVec3& origin, const Vec3& dir, const Delegate<bool (const RayCastModelHit&)> filter) override {
|
||||
RayCastModelHit castRay(const Ray& ray, const Delegate<bool (const RayCastModelHit&)> filter) override {
|
||||
PROFILE_FUNCTION();
|
||||
ASSERT(length(dir) > 0.99f && length(dir) < 1.01f);
|
||||
|
||||
RayCastModelHit hit = castRayInstancedModels(origin, dir, filter);
|
||||
RayCastModelHit hit = castRayInstancedModels(ray, filter);
|
||||
double cur_dist = hit.is_hit ? hit.t : DBL_MAX;
|
||||
|
||||
const World& world = getWorld();
|
||||
|
@ -2659,12 +2658,12 @@ struct RenderModuleImpl final : RenderModule {
|
|||
const EntityRef entity{i};
|
||||
const Transform& tr = world.getTransform(entity);
|
||||
float radius = r.model->getOriginBoundingRadius();
|
||||
const double dist = length(tr.pos - origin);
|
||||
const double dist = length(tr.pos - ray.origin);
|
||||
if (dist - radius * maximum(tr.scale.x, tr.scale.y, tr.scale.z) > cur_dist) continue;
|
||||
|
||||
const Transform& inv_tr = tr.inverted();
|
||||
const Vec3 ray_origin_model_space = Vec3(inv_tr.transform(origin));
|
||||
const Vec3 ray_dir_model_space = normalize(inv_tr.transformVector(dir));
|
||||
const Vec3 ray_origin_model_space = Vec3(inv_tr.transform(ray.origin));
|
||||
const Vec3 ray_dir_model_space = normalize(inv_tr.transformVector(ray.dir));
|
||||
|
||||
float intersection_t;
|
||||
if (getRaySphereIntersection(ray_origin_model_space, ray_dir_model_space, Vec3::ZERO, radius, intersection_t) && intersection_t >= 0) {
|
||||
|
@ -2675,13 +2674,13 @@ struct RenderModuleImpl final : RenderModule {
|
|||
if (new_hit.is_hit) {
|
||||
const Vec3 hit_pos_model_space = Vec3(new_hit.origin + new_hit.dir * new_hit.t);
|
||||
const DVec3 new_hit_pos = tr.transform(hit_pos_model_space);
|
||||
const float new_t = (float)length(origin - new_hit_pos);
|
||||
const float new_t = (float)length(ray.origin - new_hit_pos);
|
||||
if (!hit.is_hit || new_t < hit.t) {
|
||||
new_hit.entity = entity;
|
||||
new_hit.component_type = MODEL_INSTANCE_TYPE;
|
||||
hit = new_hit;
|
||||
hit.origin = origin;
|
||||
hit.dir = dir;
|
||||
hit.origin = ray.origin;
|
||||
hit.dir = ray.dir;
|
||||
hit.t = new_t;
|
||||
hit.is_hit = true;
|
||||
cur_dist = hit.t;
|
||||
|
@ -2691,14 +2690,14 @@ struct RenderModuleImpl final : RenderModule {
|
|||
}
|
||||
}
|
||||
|
||||
const RayCastModelHit pg_hit = castRayProceduralGeometry(origin, dir, filter);
|
||||
const RayCastModelHit pg_hit = castRayProceduralGeometry(ray, filter);
|
||||
if (pg_hit.is_hit && (pg_hit.t < hit.t || !hit.is_hit)) {
|
||||
hit = pg_hit;
|
||||
hit.component_type = PROCEDURAL_GEOM_TYPE;
|
||||
}
|
||||
|
||||
for (auto* terrain : m_terrains) {
|
||||
RayCastModelHit terrain_hit = terrain->castRay(origin, dir);
|
||||
RayCastModelHit terrain_hit = terrain->castRay(ray);
|
||||
if (terrain_hit.is_hit && (!hit.is_hit || terrain_hit.t < hit.t)) {
|
||||
terrain_hit.component_type = TERRAIN_TYPE;
|
||||
terrain_hit.entity = terrain->getEntity();
|
||||
|
@ -2707,8 +2706,8 @@ struct RenderModuleImpl final : RenderModule {
|
|||
}
|
||||
}
|
||||
|
||||
hit.origin = origin;
|
||||
hit.dir = dir;
|
||||
hit.origin = ray.origin;
|
||||
hit.dir = ray.dir;
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
@ -3360,10 +3359,20 @@ void RenderModule::reflect() {
|
|||
}
|
||||
};
|
||||
|
||||
reflection::structure<Ray>("Ray")
|
||||
.member<&Ray::origin>("origin")
|
||||
.member<&Ray::dir>("dir");
|
||||
|
||||
reflection::structure<RayCastModelHit>("RayCastModelHit")
|
||||
.member<&RayCastModelHit::is_hit>("is_hit")
|
||||
.member<&RayCastModelHit::t>("t")
|
||||
.member<&RayCastModelHit::entity>("entity");
|
||||
|
||||
LUMIX_MODULE(RenderModuleImpl, "renderer")
|
||||
.LUMIX_FUNC(addDebugCross)
|
||||
.LUMIX_FUNC(addDebugLine)
|
||||
.LUMIX_FUNC(addDebugTriangle)
|
||||
.function<(RayCastModelHit (RenderModuleImpl::*)(const Ray&, EntityPtr))&RenderModuleImpl::castRay>("castRay", "RenderModuleImpl::castRay")
|
||||
.LUMIX_FUNC(setActiveCamera)
|
||||
.LUMIX_CMP(ProceduralGeometry, "procedural_geom", "Render / Procedural geometry")
|
||||
.LUMIX_PROP(ProceduralGeometryMaterial, "Material").resourceAttribute(Material::TYPE)
|
||||
|
@ -3391,6 +3400,7 @@ void RenderModule::reflect() {
|
|||
.LUMIX_PROP(ParticleSystemPath, "Source").resourceAttribute(ParticleSystemResource::TYPE)
|
||||
.LUMIX_CMP(Camera, "camera", "Render / Camera")
|
||||
.icon(ICON_FA_CAMERA)
|
||||
.function<&RenderModule::getCameraRay>("getRay", "getCameraRay")
|
||||
.var_prop<&RenderModule::getCamera, &Camera::fov>("FOV").radiansAttribute()
|
||||
.var_prop<&RenderModule::getCamera, &Camera::near>("Near").minAttribute(0)
|
||||
.var_prop<&RenderModule::getCamera, &Camera::far>("Far").minAttribute(0)
|
||||
|
|
|
@ -280,6 +280,7 @@ enum class RenderModuleVersion : i32 {
|
|||
LATEST
|
||||
};
|
||||
|
||||
|
||||
struct LUMIX_RENDERER_API RenderModule : IModule
|
||||
{
|
||||
static UniquePtr<RenderModule> createInstance(Renderer& renderer,
|
||||
|
@ -289,10 +290,10 @@ struct LUMIX_RENDERER_API RenderModule : IModule
|
|||
static void registerLuaAPI(lua_State* L, Renderer& renderer);
|
||||
static void reflect();
|
||||
|
||||
virtual RayCastModelHit castRay(const DVec3& origin, const Vec3& dir, const Delegate<bool (const RayCastModelHit&)> filter) = 0;
|
||||
virtual RayCastModelHit castRay(const DVec3& origin, const Vec3& dir, EntityPtr ignore) = 0;
|
||||
virtual RayCastModelHit castRayTerrain(const DVec3& origin, const Vec3& dir) = 0;
|
||||
virtual RayCastModelHit castRayInstancedModels(const DVec3& ray_origin, const Vec3& ray_dir, const Delegate<bool (const RayCastModelHit&)>& filter) = 0;
|
||||
virtual RayCastModelHit castRay(const Ray& ray, const Delegate<bool (const RayCastModelHit&)> filter) = 0;
|
||||
virtual RayCastModelHit castRay(const Ray& ray, EntityPtr ignore) = 0;
|
||||
virtual RayCastModelHit castRayTerrain(const Ray& ray) = 0;
|
||||
virtual RayCastModelHit castRayInstancedModels(const Ray& ray, const Delegate<bool (const RayCastModelHit&)>& filter) = 0;
|
||||
virtual struct Ray getCameraRay(EntityRef entity, const Vec2& screen_pos) = 0;
|
||||
|
||||
virtual void setActiveCamera(EntityRef camera) = 0;
|
||||
|
|
|
@ -368,7 +368,6 @@ struct RendererImpl final : Renderer
|
|||
: m_engine(engine)
|
||||
, m_allocator(engine.getAllocator(), "renderer")
|
||||
, m_texture_manager("textures", *this, m_allocator)
|
||||
, m_pipeline_manager("pipelines", *this, m_allocator)
|
||||
, m_model_manager("models", *this, m_allocator)
|
||||
, m_particle_emitter_manager("particle emitters", *this, m_allocator)
|
||||
, m_material_manager(*this, m_allocator)
|
||||
|
@ -404,7 +403,6 @@ struct RendererImpl final : Renderer
|
|||
~RendererImpl()
|
||||
{
|
||||
m_particle_emitter_manager.destroy();
|
||||
m_pipeline_manager.destroy();
|
||||
m_texture_manager.destroy();
|
||||
m_model_manager.destroy();
|
||||
m_material_manager.destroy();
|
||||
|
@ -557,7 +555,6 @@ struct RendererImpl final : Renderer
|
|||
stream.update(mb.buffer, &default_mat, sizeof(default_mat));
|
||||
|
||||
ResourceManagerHub& manager = m_engine.getResourceManager();
|
||||
m_pipeline_manager.create(PipelineResource::TYPE, manager);
|
||||
m_texture_manager.create(Texture::TYPE, manager);
|
||||
m_model_manager.create(Model::TYPE, manager);
|
||||
m_material_manager.create(Material::TYPE, manager);
|
||||
|
@ -1003,7 +1000,6 @@ struct RendererImpl final : Renderer
|
|||
MaterialManager m_material_manager;
|
||||
RenderResourceManager<Model> m_model_manager;
|
||||
RenderResourceManager<ParticleSystemResource> m_particle_emitter_manager;
|
||||
RenderResourceManager<PipelineResource> m_pipeline_manager;
|
||||
RenderResourceManager<Shader> m_shader_manager;
|
||||
RenderResourceManager<Texture> m_texture_manager;
|
||||
Array<u32> m_free_sort_keys;
|
||||
|
|
|
@ -475,7 +475,7 @@ void Terrain::setHeight(int x, int z, float h)
|
|||
}
|
||||
|
||||
|
||||
RayCastModelHit Terrain::castRay(const DVec3& origin, const Vec3& dir)
|
||||
RayCastModelHit Terrain::castRay(const Ray& ray)
|
||||
{
|
||||
RayCastModelHit hit;
|
||||
hit.is_hit = false;
|
||||
|
@ -485,8 +485,8 @@ RayCastModelHit Terrain::castRay(const DVec3& origin, const Vec3& dir)
|
|||
const World& world = m_module.getWorld();
|
||||
const Quat rot = world.getRotation(m_entity);
|
||||
const DVec3 pos = world.getPosition(m_entity);
|
||||
const Vec3 rel_dir = rot.rotate(dir);
|
||||
const Vec3 terrain_to_ray = Vec3(origin - pos);
|
||||
const Vec3 rel_dir = rot.rotate(ray.dir);
|
||||
const Vec3 terrain_to_ray = Vec3(ray.origin - pos);
|
||||
const Vec3 rel_origin = rot.conjugated().rotate(terrain_to_ray);
|
||||
|
||||
Vec3 start;
|
||||
|
@ -514,15 +514,15 @@ RayCastModelHit Terrain::castRay(const DVec3& origin, const Vec3& dir)
|
|||
Vec3 p3(x, getHeight(x, z + m_scale.x), z + m_scale.x);
|
||||
if (getRayTriangleIntersection(rel_origin, rel_dir, p0, p1, p2, &t)) {
|
||||
hit.is_hit = true;
|
||||
hit.origin = origin;
|
||||
hit.dir = dir;
|
||||
hit.origin = ray.origin;
|
||||
hit.dir = ray.dir;
|
||||
hit.t = t;
|
||||
return hit;
|
||||
}
|
||||
if (getRayTriangleIntersection(rel_origin, rel_dir, p0, p2, p3, &t)) {
|
||||
hit.is_hit = true;
|
||||
hit.origin = origin;
|
||||
hit.dir = dir;
|
||||
hit.origin = ray.origin;
|
||||
hit.dir = ray.dir;
|
||||
hit.t = t;
|
||||
return hit;
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ struct Terrain {
|
|||
void setGrassTypeRotationMode(int index, GrassType::RotationMode mode);
|
||||
void setMaterial(Material* material);
|
||||
|
||||
RayCastModelHit castRay(const DVec3& origin, const Vec3& dir);
|
||||
RayCastModelHit castRay(const Ray& ray);
|
||||
void serialize(OutputMemoryStream& serializer);
|
||||
void deserialize(EntityRef entity, InputMemoryStream& serializer, World& world, RenderModule& module, i32 version);
|
||||
|
||||
|
|
Loading…
Reference in New Issue