mirror of
https://github.com/Nexoniarz/Fry3DX.git
synced 2026-11-03 04:24:26 +00:00
0.8.1: project.json holds the version, the links, who made it and what it's built on (CMake reads it into fry_project.h and Windows' file details, which had stayed at 0.5.0); the About box lists the creators, the Help menu the website, reporting a problem and the newest version. Steadier far out: the grid's line sizes go by each pixel (not the focus, which jumps between the ground and the sky as you fly, popping every set at once), the far plane doesn't follow that focus when flying, and a wheel notch is at most twice as far as the nearest thing; the site's 0.8.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
b2fc0437bc
commit
ee56ed4005
13 changed files with 176 additions and 64 deletions
|
|
@ -1,5 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.25)
|
||||
project(Fry3DX VERSION 0.8.0 LANGUAGES C CXX)
|
||||
include(cmake/Project.cmake) # project.json: the version, links, creators
|
||||
project(Fry3DX VERSION ${FRY_VERSION} LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # (no C++ modules; the scan can pick up a different clang than the NDK's)
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_link_options(-rdynamic) # function names in crash reports
|
||||
|
|
|
|||
81
cmake/Project.cmake
Normal file
81
cmake/Project.cmake
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# project.json, read before project(): FRY_VERSION and the rest as FRY_<KEY>; fry_project_header()
|
||||
# writes them as C++ constants (fry_project.h) and Windows' file details (fry3dx.rc).
|
||||
set(FRY_PROJECT_JSON ${CMAKE_CURRENT_LIST_DIR}/../project.json)
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${FRY_PROJECT_JSON})
|
||||
file(READ ${FRY_PROJECT_JSON} FRY_JSON)
|
||||
foreach(key name long version tagline description website repo issues releases license copyright company look)
|
||||
string(TOUPPER ${key} upper)
|
||||
string(JSON FRY_${upper} GET "${FRY_JSON}" ${key})
|
||||
endforeach()
|
||||
|
||||
# out: the header's path; rc: Windows' file details (the version as 0,8,1,0 too).
|
||||
function(fry_project_header out rc)
|
||||
set(h "// Made by CMake from project.json: change that, not this.\n#pragma once\n#include <span>\n\nnamespace fry::project {\n")
|
||||
foreach(key name long version tagline description website repo issues releases license copyright company look)
|
||||
string(TOUPPER ${key} upper)
|
||||
set(ident ${key})
|
||||
if(key STREQUAL "long")
|
||||
set(ident long_) # (a C++ word)
|
||||
endif()
|
||||
string(APPEND h "inline constexpr const char* ${ident} = R\"fry(${FRY_${upper}})fry\";\n")
|
||||
endforeach()
|
||||
string(APPEND h "\nstruct Creator {\n const char* name;\n const char* role;\n const char* url;\n};\ninline constexpr Creator kCreators[] = {\n")
|
||||
string(JSON n LENGTH "${FRY_JSON}" creators)
|
||||
math(EXPR last "${n} - 1")
|
||||
foreach(i RANGE ${last})
|
||||
string(JSON who GET "${FRY_JSON}" creators ${i} name)
|
||||
string(JSON role ERROR_VARIABLE none GET "${FRY_JSON}" creators ${i} role)
|
||||
string(JSON url ERROR_VARIABLE none GET "${FRY_JSON}" creators ${i} url)
|
||||
if(role MATCHES "NOTFOUND$")
|
||||
set(role "")
|
||||
endif()
|
||||
if(url MATCHES "NOTFOUND$")
|
||||
set(url "")
|
||||
endif()
|
||||
string(APPEND h " {R\"fry(${who})fry\", R\"fry(${role})fry\", R\"fry(${url})fry\"},\n")
|
||||
endforeach()
|
||||
string(APPEND h "};\ninline constexpr std::span<const Creator> creators{kCreators};\n\n// What it's built on (for the About box).\ninline constexpr const char* builtWith = R\"fry(")
|
||||
string(JSON n LENGTH "${FRY_JSON}" builtWith)
|
||||
math(EXPR last "${n} - 1")
|
||||
foreach(i RANGE ${last})
|
||||
string(JSON part GET "${FRY_JSON}" builtWith ${i})
|
||||
if(i GREATER 0)
|
||||
if(i EQUAL last)
|
||||
string(APPEND h " and ")
|
||||
else()
|
||||
string(APPEND h ", ")
|
||||
endif()
|
||||
endif()
|
||||
string(APPEND h "${part}")
|
||||
endforeach()
|
||||
string(APPEND h ")fry\";\n} // namespace fry::project\n")
|
||||
file(CONFIGURE OUTPUT ${out} CONTENT "${h}" @ONLY)
|
||||
|
||||
string(REPLACE "." "," commas "${FRY_VERSION}")
|
||||
file(CONFIGURE OUTPUT ${rc} CONTENT "// Made by CMake from project.json (Windows: the program's icon and details, Explorer's Properties).
|
||||
1 ICON \"${PROJECT_SOURCE_DIR}/branding/fry3dx.ico\"
|
||||
1 VERSIONINFO
|
||||
FILEVERSION ${commas},0
|
||||
PRODUCTVERSION ${commas},0
|
||||
BEGIN
|
||||
BLOCK \"StringFileInfo\"
|
||||
BEGIN
|
||||
BLOCK \"040904b0\"
|
||||
BEGIN
|
||||
VALUE \"CompanyName\", \"${FRY_COMPANY}\"
|
||||
VALUE \"FileDescription\", \"${FRY_NAME} - ${FRY_LONG}\"
|
||||
VALUE \"FileVersion\", \"${FRY_VERSION}\"
|
||||
VALUE \"InternalName\", \"fry3dx\"
|
||||
VALUE \"LegalCopyright\", \"${FRY_COPYRIGHT}, ${FRY_LICENSE}\"
|
||||
VALUE \"OriginalFilename\", \"fry3dx.exe\"
|
||||
VALUE \"ProductName\", \"${FRY_NAME}\"
|
||||
VALUE \"ProductVersion\", \"${FRY_VERSION}\"
|
||||
END
|
||||
END
|
||||
BLOCK \"VarFileInfo\"
|
||||
BEGIN
|
||||
VALUE \"Translation\", 0x409, 1200
|
||||
END
|
||||
END
|
||||
" @ONLY)
|
||||
endfunction()
|
||||
|
|
@ -129,6 +129,7 @@ fry.frame()`,
|
|||
},
|
||||
|
||||
versions: [
|
||||
{ v: "0.8.1", date: "2026-10-21", items: ["Fixes", "Close up to big or long flat shapes the view no longer breaks into blocks, jitters or loses the sky and grid", "The grid drawn as in Blender: every size of line everywhere it's far enough apart, smooth, nothing smeared or popping as you move", "Far from the middle of the scene: steadier, and the wheel doesn't leap", "Help menu: the website, reporting a problem, the newest version; the About box lists who made it"] },
|
||||
{ v: "0.8", date: "2026-10-21", items: ["Quicker to use, exact to size", "Find any command by name (F3), the tools round the mouse (Space), your own keys, the undo history, workspaces", "Typed sizes while dragging, snapping, measuring, a line's length while drawing", "Cuts you can still move; combining that's exact", "3D text, spin and screw, copies along a path, crease, edge slide, mirror editing", "Import STL, OBJ, 3MF and glTF", "Print: a scaler, thin walls, a slice preview, repair all at once", "Painting both sides and inside a stencil; plug-ins can add mouse tools", "A fly camera as in games (right drag, WASD, the wheel forward and back, Shift + wheel for speed), or the orbiting one (Shift+C)", "Smoother: dragging settings in Properties, a grid that doesn't crawl or jump, clean close-ups in Rendered", "Far away things no longer vanish; steadier and smoother on phones, which stay sideways"] },
|
||||
{ v: "0.7", date: "2026-10-21", items: ["Steadier and tidier", "Cutting a shape inside an earlier cut no longer crashes, and cuts come out closed", "Edges hidden behind the surface stay hidden on big or cut-up shapes", "Every panel has a least size, so it stays readable; the first layout fits small windows", "Eye and padlock buttons in Layers; the tabs fit narrow windows", "A failed tool keeps your redo"] },
|
||||
{ v: "0.6", date: "2026-10-20", items: ["Sculpting, scripts and a Mac app", "Sculpting: raise, puff out, smooth, flatten, pinch and grab", "Materials shown in the view, sixteen to start from", "Scripts: Lua and a Script panel, with examples, kept in the .fry", "Plug-ins: menu commands and materials, three to start with", "Your own materials", "Soft selection, bridge, push / pull, smooth points, show only the selected", "macOS: one app for Apple silicon and Intel", "A new look (Niveus): light and dark, following the desktop", "A new logo", "Drop a file on the window to open it"] },
|
||||
|
|
|
|||
|
|
@ -211,10 +211,10 @@ void Renderer::drawSprite(const glm::vec3& at, float size, const glm::vec4& colo
|
|||
list.push_back({glm::vec4(at, size * 0.5f), color, glm::vec4(0, 0, 0, rotation), glm::vec4(0, 0, 0, tex)});
|
||||
}
|
||||
|
||||
void Renderer::drawGrid(const glm::vec3& centre, const glm::vec3& u, const glm::vec3& v, float first, const glm::vec3& look, float reach) {
|
||||
void Renderer::drawGrid(const glm::vec3& centre, const glm::vec3& u, const glm::vec3& v, float metre, const glm::vec3& look, float reach) {
|
||||
if (packet_.sprites.size() >= 8192) return;
|
||||
// (colour.a < 0 marks it; sprite.vert / sprite.frag)
|
||||
packet_.sprites.push_back({glm::vec4(centre, reach), glm::vec4(look, -1.0f), glm::vec4(u, first), glm::vec4(v, 0.0f)});
|
||||
packet_.sprites.push_back({glm::vec4(centre, reach), glm::vec4(look, -1.0f), glm::vec4(u, metre), glm::vec4(v, 0.0f)});
|
||||
}
|
||||
|
||||
void Renderer::drawStreak(const glm::vec3& from, const glm::vec3& to, float width, const glm::vec4& color, TextureId texture, bool additive, float widthTo) {
|
||||
|
|
|
|||
|
|
@ -102,10 +102,10 @@ public:
|
|||
// each end turned to face the eye as much as it can (rain; lines drawn in pieces meet exactly).
|
||||
void drawStreak(const glm::vec3& from, const glm::vec3& to, float width, const glm::vec4& color, TextureId texture, bool additive = false, float widthTo = -1.0f);
|
||||
// A grid of lines on the plane through `centre` along u and v (unit), drawn for each pixel:
|
||||
// four sets `first` × 10 apart, each showing by how far apart its lines are on the screen,
|
||||
// the axes coloured; look: the lines' shade (0 dark, 1 light), how faint, how strong; fading
|
||||
// out `reach` from the centre.
|
||||
void drawGrid(const glm::vec3& centre, const glm::vec3& u, const glm::vec3& v, float first, const glm::vec3& look, float reach);
|
||||
// every 10^n metres (`metre`: units in one), each set showing by how far apart its lines are
|
||||
// on the screen, the axes coloured; look: the lines' shade (0 dark, 1 light), how faint, how
|
||||
// strong; fading out `reach` from the centre.
|
||||
void drawGrid(const glm::vec3& centre, const glm::vec3& u, const glm::vec3& v, float metre, const glm::vec3& look, float reach);
|
||||
// skin: one matrix per joint (anim::skinMatrices) for skinned models; ignored otherwise.
|
||||
// lighting: probe light for moving things (nullptr = lightmap or simple sun shading).
|
||||
void drawModel(ModelId model, const glm::mat4& transform, const glm::vec4& tint = glm::vec4(1.0f),
|
||||
|
|
|
|||
|
|
@ -393,20 +393,22 @@ uniform sampler2D u_albedo;
|
|||
uniform vec4 u_color, u_posSize, u_right, u_up;
|
||||
out vec4 o_color;
|
||||
// A grid (a sprite with colour.a < 0), worked out for each pixel where it lies on its plane:
|
||||
// four sets of lines each `first` × 10 apart, each set showing by how far apart its lines are on
|
||||
// the screen (none where they crowd together, stronger where they're far apart), lines about a
|
||||
// pixel wide, smooth; the axes through the middle in the colour of the world's axis they run along.
|
||||
// lines every 10^n metres (`metre`: units in one), the four sets from the finest that isn't
|
||||
// crowded together here, each showing by how far apart its lines are on the screen (none where
|
||||
// they crowd, stronger where they're far apart: nothing jumps as the view moves), about a pixel
|
||||
// wide, smooth; the axes through the middle in the colour of the world's axis they run along.
|
||||
// look: x the lines' shade (0 dark, 1 light), y how faint, z how strong; reach: it fades out there.
|
||||
vec3 gridAxisColor(vec3 d) {
|
||||
d = abs(d);
|
||||
return d.x > 0.5 ? vec3(0.9, 0.25, 0.25) : d.y > 0.5 ? vec3(0.3, 0.75, 0.25) : vec3(0.25, 0.45, 0.95);
|
||||
}
|
||||
vec4 gridColor(vec3 w, vec3 centre, vec3 u, vec3 v, float first, vec3 look, float reach) {
|
||||
vec4 gridColor(vec3 w, vec3 centre, vec3 u, vec3 v, float metre, vec3 look, float reach) {
|
||||
vec2 c = vec2(dot(w, u), dot(w, v));
|
||||
vec2 fw = max(fwidth(c), vec2(1e-9));
|
||||
float finest = floor(log(min(fw.x, fw.y) * 5.0 / metre) / log(10.0)); // (10^this m: 5 pixels apart or more)
|
||||
float lines = 0.0;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
float s = first * pow(10.0, float(k));
|
||||
float s = metre * pow(10.0, finest + float(k));
|
||||
vec2 apart = s / fw; // (pixels between this set's lines, each way)
|
||||
vec2 off = abs(fract(c / s + 0.5) - 0.5) * apart; // (pixels to the nearest of them)
|
||||
vec2 strong = smoothstep(20.0, 160.0, apart);
|
||||
|
|
|
|||
|
|
@ -11,20 +11,22 @@ PUSH_BLOCK {
|
|||
layout(location = 0) in vec2 v_uv;
|
||||
layout(location = 1) in vec3 v_world;
|
||||
// A grid (a sprite with colour.a < 0), worked out for each pixel where it lies on its plane:
|
||||
// four sets of lines each `first` × 10 apart, each set showing by how far apart its lines are on
|
||||
// the screen (none where they crowd together, stronger where they're far apart), lines about a
|
||||
// pixel wide, smooth; the axes through the middle in the colour of the world's axis they run along.
|
||||
// lines every 10^n metres (`metre`: units in one), the four sets from the finest that isn't
|
||||
// crowded together here, each showing by how far apart its lines are on the screen (none where
|
||||
// they crowd, stronger where they're far apart: nothing jumps as the view moves), about a pixel
|
||||
// wide, smooth; the axes through the middle in the colour of the world's axis they run along.
|
||||
// look: x the lines' shade (0 dark, 1 light), y how faint, z how strong; reach: it fades out there.
|
||||
vec3 gridAxisColor(vec3 d) {
|
||||
d = abs(d);
|
||||
return d.x > 0.5 ? vec3(0.9, 0.25, 0.25) : d.y > 0.5 ? vec3(0.3, 0.75, 0.25) : vec3(0.25, 0.45, 0.95);
|
||||
}
|
||||
vec4 gridColor(vec3 w, vec3 centre, vec3 u, vec3 v, float first, vec3 look, float reach) {
|
||||
vec4 gridColor(vec3 w, vec3 centre, vec3 u, vec3 v, float metre, vec3 look, float reach) {
|
||||
vec2 c = vec2(dot(w, u), dot(w, v));
|
||||
vec2 fw = max(fwidth(c), vec2(1e-9));
|
||||
float finest = floor(log(min(fw.x, fw.y) * 5.0 / metre) / log(10.0)); // (10^this m: 5 pixels apart or more)
|
||||
float lines = 0.0;
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
float s = first * pow(10.0, float(k));
|
||||
float s = metre * pow(10.0, finest + float(k));
|
||||
vec2 apart = s / fw; // (pixels between this set's lines, each way)
|
||||
vec2 off = abs(fract(c / s + 0.5) - 0.5) * apart; // (pixels to the nearest of them)
|
||||
vec2 strong = smoothstep(20.0, 160.0, apart);
|
||||
|
|
@ -43,7 +45,7 @@ vec4 gridColor(vec3 w, vec3 centre, vec3 u, vec3 v, float first, vec3 look, floa
|
|||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
void main() {
|
||||
if (pc.color.a < 0.0) { // a grid: right.w its finest step, color.rgb its look, posSize.w how far it reaches
|
||||
if (pc.color.a < 0.0) { // a grid: right.w the units in a metre, color.rgb its look, posSize.w how far it reaches
|
||||
o_color = gridColor(v_world, pc.posSize.xyz, normalize(pc.right.xyz), normalize(pc.up.xyz), pc.right.w, pc.color.rgb, pc.posSize.w);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
20
project.json
Normal file
20
project.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"_": "Fry3DX's details, in one place: the build reads them (the version, the About box, the Help menu, Windows' file details). Change them here; CMake picks them up on the next build.",
|
||||
"name": "Fry3DX",
|
||||
"long": "Frying 3D Extreme",
|
||||
"version": "0.8.1",
|
||||
"tagline": "A 3D modeller that does what you'd expect.",
|
||||
"description": "A 3D modeller that does what you'd expect: pick a tool, click and drag. Model, sculpt, paint, render and get it ready to print, and write a script when clicking gets repetitive.",
|
||||
"website": "https://nexoniarz.github.io/Fry3DX/",
|
||||
"repo": "https://github.com/Nexoniarz/Fry3DX",
|
||||
"issues": "https://github.com/Nexoniarz/Fry3DX/issues",
|
||||
"releases": "https://github.com/Nexoniarz/Fry3DX/releases/latest",
|
||||
"license": "Apache License 2.0",
|
||||
"copyright": "Copyright 2026 Nexoniarz",
|
||||
"company": "Nexoniarz",
|
||||
"look": "Niveus",
|
||||
"creators": [
|
||||
{ "name": "Nexoniarz", "role": "Made it: the idea, the design, the code, the look", "url": "https://github.com/Nexoniarz" }
|
||||
],
|
||||
"builtWith": ["SDL 3", "Dear ImGui", "Lua 5.4", "GLM", "Manifold", "zstd", "stb", "volk", "VMA"]
|
||||
}
|
||||
|
|
@ -47,12 +47,13 @@ else()
|
|||
add_executable(fry3dx ${FRY_APP_SOURCES})
|
||||
endif()
|
||||
if(WIN32) # a window program (no console window), with its icon
|
||||
target_sources(fry3dx PRIVATE fry3dx.rc)
|
||||
target_sources(fry3dx PRIVATE ${CMAKE_BINARY_DIR}/generated/fry3dx.rc)
|
||||
set_target_properties(fry3dx PROPERTIES WIN32_EXECUTABLE ON)
|
||||
target_link_options(fry3dx PRIVATE /ENTRY:mainCRTStartup)
|
||||
endif()
|
||||
target_link_libraries(fry3dx PRIVATE fry_core fry_script keel stb)
|
||||
target_compile_definitions(fry3dx PRIVATE FRY_VERSION="${PROJECT_VERSION}")
|
||||
fry_project_header(${CMAKE_BINARY_DIR}/generated/fry_project.h ${CMAKE_BINARY_DIR}/generated/fry3dx.rc) # (project.json)
|
||||
target_include_directories(fry3dx PRIVATE ${CMAKE_BINARY_DIR}/generated)
|
||||
add_dependencies(fry3dx content)
|
||||
foreach(t fry_core fry_script fry3dx)
|
||||
if(MSVC)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Fry3DX: the panels: layers, properties, menus, the commands and their keys.
|
||||
#include "app.h"
|
||||
#include "fry_project.h"
|
||||
|
||||
using namespace fry;
|
||||
namespace stdfs = std::filesystem;
|
||||
|
|
@ -788,7 +789,12 @@ auto App::menus() -> void {
|
|||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("Keys and mouse", "F1")) showHelp_ = true;
|
||||
commandItem("help.search");
|
||||
if (ImGui::MenuItem("About Fry3DX")) showAbout_ = true;
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Website")) SDL_OpenURL(project::website);
|
||||
if (ImGui::MenuItem("Report a problem")) SDL_OpenURL(project::issues);
|
||||
if (ImGui::MenuItem("Newest version")) SDL_OpenURL(project::releases);
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(std::format("About {}", project::name).c_str())) showAbout_ = true;
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Fry3DX: scripts, your own materials, plug-ins, the windows that go with them.
|
||||
#include "app.h"
|
||||
#include "fry_project.h"
|
||||
|
||||
using namespace fry;
|
||||
namespace stdfs = std::filesystem;
|
||||
|
|
@ -747,14 +748,13 @@ auto App::aboutWindow() -> void {
|
|||
logoImage(logo);
|
||||
ImGui::Dummy(ImVec2(0, 6));
|
||||
ImGui::PushFont(keel::ui::font(keel::ui::Font::Title), 30.0f);
|
||||
centred("Fry3DX", roleColor(Role::Text));
|
||||
centred(project::name, roleColor(Role::Text));
|
||||
ImGui::PopFont();
|
||||
centred("Frying 3D Extreme", accentText());
|
||||
centred("Version " FRY_VERSION, roleColor(Role::TextSecondary));
|
||||
centred(project::long_, accentText());
|
||||
centred(std::format("Version {}", project::version).c_str(), roleColor(Role::TextSecondary));
|
||||
ImGui::Dummy(ImVec2(0, 8));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, roleColor(Role::TextSecondary));
|
||||
ImGui::TextWrapped("A 3D modeller that does what you'd expect: pick a tool, click and drag. Model, sculpt, paint, render and get it ready "
|
||||
"to print, and write a script when clicking gets repetitive.");
|
||||
ImGui::TextWrapped("%s", project::description);
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Dummy(ImVec2(0, 4));
|
||||
|
||||
|
|
@ -762,7 +762,7 @@ auto App::aboutWindow() -> void {
|
|||
const keel::GpuInfo gpu = r_->gpuInfo();
|
||||
const auto& machine = keel::sys::machine();
|
||||
const std::vector<std::pair<const char*, std::string>> rows = {
|
||||
{"Version", FRY_VERSION}, {"Drawn with", r_->apiName()}, {"Graphics", gpu.name.empty() ? "?" : gpu.name}, {"System", machine.os}, {"Processor", machine.cpu},
|
||||
{"Version", project::version}, {"Drawn with", r_->apiName()}, {"Graphics", gpu.name.empty() ? "?" : gpu.name}, {"System", machine.os}, {"Processor", machine.cpu},
|
||||
{"Plug-ins", std::format("{} loaded", std::count_if(plugins_.begin(), plugins_.end(), [](const PluginEntry& e) { return e.p && e.error.empty(); }))}};
|
||||
ImGui::BeginChild("details", ImVec2(0, 0), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_AutoResizeY);
|
||||
if (ImGui::BeginTable("details", 2, ImGuiTableFlags_SizingFixedFit)) {
|
||||
|
|
@ -781,21 +781,39 @@ auto App::aboutWindow() -> void {
|
|||
ImGui::Dummy(ImVec2(0, 4));
|
||||
const float bw = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x * 2) / 3;
|
||||
pushAccent();
|
||||
if (ImGui::Button("Website", ImVec2(bw, 0))) SDL_OpenURL("https://nexoniarz.github.io/Fry3DX/");
|
||||
if (ImGui::Button("Website", ImVec2(bw, 0))) SDL_OpenURL(project::website);
|
||||
popAccent();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Source on GitHub", ImVec2(bw, 0))) SDL_OpenURL("https://github.com/Nexoniarz/Fry3DX");
|
||||
if (ImGui::Button("Source on GitHub", ImVec2(bw, 0))) SDL_OpenURL(project::repo);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Copy details", ImVec2(bw, 0))) {
|
||||
std::string text = "Fry3DX";
|
||||
std::string text = project::name;
|
||||
for (const auto& [k, v] : rows) text += std::format("\n{}: {}", k, v);
|
||||
SDL_SetClipboardText(text.c_str());
|
||||
say("The details are copied: paste them into a bug report");
|
||||
}
|
||||
// Who made it (project.json's creators: a name with a link opens it).
|
||||
ImGui::Dummy(ImVec2(0, 6));
|
||||
ImGui::TextColored(roleColor(Role::TextTertiary), "Made by");
|
||||
for (const project::Creator& c : project::creators) {
|
||||
ImGui::PushID(c.name);
|
||||
if (*c.url) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, accentText());
|
||||
if (ImGui::Selectable(c.name, false, ImGuiSelectableFlags_None, ImVec2(ImGui::CalcTextSize(c.name).x, 0))) SDL_OpenURL(c.url);
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", c.url);
|
||||
} else {
|
||||
ImGui::TextUnformatted(c.name);
|
||||
}
|
||||
if (*c.role) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(roleColor(Role::TextSecondary), " %s", c.role);
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::Dummy(ImVec2(0, 4));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, roleColor(Role::TextTertiary));
|
||||
ImGui::TextWrapped("Made by Nexoniarz, open source (Apache License 2.0). Built on SDL 3, Dear ImGui, Lua 5.4, GLM, zstd, stb, volk and VMA; "
|
||||
"the look is Niveus.");
|
||||
ImGui::TextWrapped("Open source (%s). Built on %s; the look is %s.", project::license, project::builtWith, project::look);
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,7 +285,9 @@ auto App::updateCamera(ImGuiIO& io) -> void {
|
|||
float size = 0.0f; // (the biggest object's size: the least step is a little of it)
|
||||
for (const Object& o : scene_.objects)
|
||||
size = std::max(size, reachOf(o).radius * std::max({std::abs(o.scale.x), std::abs(o.scale.y), std::abs(o.scale.z)}));
|
||||
const float step = std::clamp(std::max(dist_ * 0.2f, size * 0.05f), 0.001f, 500.0f) * fry_movespeed.f();
|
||||
// (what's ahead: no further than ten times how far the nearest thing is, so with only
|
||||
// the sky or the far ground ahead a notch doesn't leap)
|
||||
const float step = std::clamp(std::max(std::min(dist_, nearest_ * 10.0f) * 0.2f, size * 0.05f), 0.001f, 500.0f) * fry_movespeed.f();
|
||||
target_ += viewDir() * step * io.MouseWheel;
|
||||
refocus();
|
||||
}
|
||||
|
|
@ -334,7 +336,10 @@ auto App::nearFar() -> glm::vec2 {
|
|||
// the nearer it is, the more surfaces flicker through each other. Nothing is nearer than the
|
||||
// nearest thing, and a quarter of the way to it keeps even the screen's corners clear of it)
|
||||
const float nearM = std::clamp(std::max(viewScale() * 0.005f, nearest_ * 0.25f), 1e-5f, 50.0f);
|
||||
const float farM = std::max({dist_ * 60.0f, (glm::length(eye_) + reach) * 2.0f, 100.0f});
|
||||
// (far enough for the whole scene and the ground out to near the horizon; what it looks at
|
||||
// too when it turns round that (flying, that jumps between the ground and the sky as it moves))
|
||||
const bool flying = view_ == View::Perspective && fry_camera.i() != 1;
|
||||
const float farM = std::max({flying ? 0.0f : dist_ * 60.0f, (glm::length(eye_) + reach) * 2.0f, std::abs(eye_.z) * 2000.0f, 100.0f});
|
||||
return glm::vec2(nearM, farM) * kUnits;
|
||||
}
|
||||
|
||||
|
|
@ -1399,17 +1404,17 @@ auto App::draw3D(keel::Renderer& r) -> void {
|
|||
// lines come in too close together to see and fade in. Each line is drawn by the widest set
|
||||
// it belongs to (once), in pieces, each a pixel wide where it is.
|
||||
if (tab_ == Tab::Render ? renderGrid_ : showGrid_) {
|
||||
// Worked out for each pixel (as in Blender): four sets of lines from a tenth of the
|
||||
// grid step, each showing by how far apart its lines are on the screen, the axes
|
||||
// coloured; round the point under the eye, out to where the widest set ends.
|
||||
// Worked out for each pixel (as in Blender): lines every 10^n metres, each set showing by
|
||||
// how far apart its lines are on the screen, the axes coloured; round the point under the
|
||||
// eye, out to most of the way to the far plane.
|
||||
glm::vec3 p, n;
|
||||
workPlane(p, n);
|
||||
const glm::vec3 u = n.z > 0.5f ? glm::vec3(1, 0, 0) : n.x > 0.5f ? glm::vec3(0, 1, 0) : glm::vec3(1, 0, 0);
|
||||
const glm::vec3 v = glm::cross(n, u);
|
||||
const float first = gridStep() * 0.1f, reach = std::max(first * 20000.0f, nearFar_.y / kUnits * 0.5f);
|
||||
const float reach = nearFar_.y / kUnits * 0.9f;
|
||||
const glm::vec3 under = eye_ - n * glm::dot(eye_, n); // (the grid's plane goes through the origin)
|
||||
const glm::vec3 look = rendered ? glm::vec3(0.0f, 0.14f, 0.4f) : glm::vec3(1.0f, 0.05f, 0.16f); // (dark lines on the sunny ground, light ones in the grey room)
|
||||
r.drawGrid(under * kUnits, u, v, first * kUnits, look, reach * kUnits);
|
||||
r.drawGrid(under * kUnits, u, v, kUnits, look, reach * kUnits);
|
||||
}
|
||||
if (tab_ == Tab::Print) drawPrintBed(r, light);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// Windows: the program's icon and details (Explorer's Properties).
|
||||
1 ICON "../branding/fry3dx.ico"
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,5,0,0
|
||||
PRODUCTVERSION 0,5,0,0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Nexoniarz"
|
||||
VALUE "FileDescription", "Fry3DX - Frying 3D Extreme"
|
||||
VALUE "FileVersion", "0.5.0"
|
||||
VALUE "InternalName", "fry3dx"
|
||||
VALUE "LegalCopyright", "Copyright 2026 Nexoniarz, Apache License 2.0"
|
||||
VALUE "OriginalFilename", "fry3dx.exe"
|
||||
VALUE "ProductName", "Fry3DX"
|
||||
VALUE "ProductVersion", "0.5.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
Loading…
Reference in a new issue