Files
armorpaint/paint/sources/viewport.c
T
2026-08-21 22:35:41 +02:00

176 lines
6.3 KiB
C

#include "global.h"
void viewport_scale_to_bounds(f32 bounds) {
mesh_object_t *po = g_context->merged_object == NULL ? context_main_object() : g_context->merged_object;
mesh_data_t *md = po->data;
vec4_t aabb = mesh_data_calculate_aabb(md);
f32 r = math_sqrt(aabb.x * aabb.x + aabb.y * aabb.y + aabb.z * aabb.z);
po = context_main_object();
po->base->transform->dim.x = aabb.x;
po->base->transform->dim.y = aabb.y;
po->base->transform->dim.z = aabb.z;
po->base->transform->scale = (vec4_t){bounds / (float)r, bounds / (float)r, bounds / (float)r, 1.0};
po->base->transform->loc = (vec4_t){0, 0, 0, 1.0};
transform_build_matrix(po->base->transform);
for (i32 i = 0; i < po->base->children->length; ++i) {
object_t *c = po->base->children->buffer[i];
c->transform->loc = (vec4_t){0, 0, 0, 1.0};
transform_build_matrix(c->transform);
}
}
void viewport_reset() {
camera_object_t *cam = scene_camera;
for (i32 i = 0; i < _scene_raw->objects->length; ++i) {
obj_t *o = _scene_raw->objects->buffer[i];
if (string_equals(o->type, "camera_object")) {
cam->base->transform->local = mat4_from_f32_array(o->transform, 0);
transform_decompose(cam->base->transform);
cam->data->fov = g_config->camera_fov;
g_context->camera_type = 0;
cam->data->ortho = NULL;
camera_object_build_proj(cam, -1.0);
g_context->ddirty = 2;
camera_reset(-1);
transform_reset(context_main_object()->base->transform);
break;
}
}
}
void viewport_set_view(f32 x, f32 y, f32 z, f32 rx, f32 ry, f32 rz) {
g_context->paint_object->base->transform->rot = (quat_t){0, 0, 0, 1};
g_context->paint_object->base->transform->dirty = true;
camera_object_t *cam = scene_camera;
f32 dist = vec4_len(cam->base->transform->loc);
cam->base->transform->loc = (vec4_t){x * dist, y * dist, z * dist, 1.0};
cam->base->transform->rot = quat_from_euler(rx, ry, rz);
transform_build_matrix(cam->base->transform);
camera_object_build_proj(cam, -1.0);
g_context->ddirty = 2;
camera_reset(g_context->view_index_last);
}
void viewport_orbit(f32 x, f32 y) {
camera_object_t *cam = scene_camera;
f32 dist = camera_distance();
transform_move(cam->base->transform, camera_object_look_world(cam), dist);
transform_rotate(cam->base->transform, (vec4_t){0, 0, 1, 1.0}, x);
transform_rotate(cam->base->transform, camera_object_right_world(cam), y);
transform_move(cam->base->transform, camera_object_look_world(cam), -dist);
g_context->ddirty = 2;
}
void viewport_orbit_opposite() {
camera_object_t *cam = scene_camera;
vec4_t look = camera_object_look(cam);
f32 z = math_abs(look.z) - 1.0;
(z < 0.0001 && z > -0.0001) ? viewport_orbit(0, math_pi()) : viewport_orbit(math_pi(), 0);
}
void viewport_zoom(f32 f) {
camera_object_t *cam = scene_camera;
transform_move(cam->base->transform, camera_object_look(cam), f);
g_context->ddirty = 2;
}
void viewport_update_camera_type(i32 camera_type) {
camera_object_t *cam = scene_cameras->buffer[0];
if (camera_type == CAMERA_TYPE_PERSPECTIVE) {
cam->data->ortho = NULL;
}
else {
f32_array_t *f32a = f32_array_create(4);
f32 f = cam->data->fov * vec4_len(mat4_get_loc(cam->base->transform->world)) / 2.5;
f32a->buffer[0] = -2 * f;
f32a->buffer[1] = 2 * f;
f32a->buffer[2] = -2 * f * (sys_h() / (float)sys_w());
f32a->buffer[3] = 2 * f * (sys_h() / (float)sys_w());
cam->data->ortho = f32a;
}
camera_object_build_proj(cam, -1.0);
g_context->ddirty = 2;
}
void viewport_save_texture(gpu_texture_t *screenshot) {
// Save into the textures tab
if (g_project->packed_assets == NULL) {
g_project->packed_assets = any_array_create_from_raw((void *[]){}, 0);
}
i32 num = 0;
char *abs = "/packed/screenshot0.png";
for (i32 i = 0; i < g_project->packed_assets->length; ++i) {
packed_asset_t *pa = g_project->packed_assets->buffer[i];
if (string_equals(pa->name, abs)) {
i = 0;
num++;
abs = string("/packed/screenshot%d.png", num);
}
}
packed_asset_t *pa =
ALLOC_INIT(packed_asset_t, {.name = abs, .bytes = iron_encode_png(gpu_get_texture_pixels(screenshot), screenshot->width, screenshot->height, 0)});
any_array_push(g_project->packed_assets, pa);
any_map_set(data_cached_textures, abs, screenshot);
import_texture_run(abs, true);
}
void viewport_capture_screenshot() {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
gpu_texture_t *tex = rt->_image;
gpu_texture_t *screenshot = gpu_create_render_target(tex->width, tex->height, GPU_TEXTURE_FORMAT_RGBA32);
draw_begin(screenshot, false, 0);
draw_image(tex, 0, 0);
draw_end();
viewport_save_texture(screenshot);
g_context->capturing_screenshot = false;
g_context->ddirty = 2;
}
void viewport_capture_screenshot_to(gpu_texture_t *target, float x, float y, float w, float h) {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
gpu_texture_t *tex = rt->_image;
// Crop the viewport texture to a square
float size = tex->width < tex->height ? tex->width : tex->height;
float sx = (tex->width - size) / 2.0f;
float sy = (tex->height - size) / 2.0f;
draw_begin(target, false, 0);
draw_scaled_sub_image(tex, sx, sy, size, size, x, y, w, h);
draw_end();
g_context->capturing_screenshot = false;
g_context->ddirty = 2;
}
void viewport_capture_video_update(void *_) {
render_target_t *rt = any_map_get(render_path_render_targets, "last");
buffer_t *pixels = gpu_get_texture_pixels(rt->_image);
#ifdef IRON_BGRA
buffer_bgra_swap(pixels);
#endif
iron_mp4_encode(pixels);
}
void viewport_capture_video_begin() {
if (string_equals(g_project->_->filepath, "")) {
console_error(tr("Save project first"));
return;
}
viewport_recording = true;
char *path = string("%s/output.mp4", path_base_dir(g_project->_->filepath));
render_target_t *rt = any_map_get(render_path_render_targets, "last");
iron_mp4_begin(path, rt->_image->width, rt->_image->height);
sys_notify_on_update(viewport_capture_video_update, NULL);
}
void viewport_capture_video_end() {
sys_remove_update(viewport_capture_video_update);
iron_mp4_end();
viewport_recording = false;
}