The Update(TM), Part 2
This commit is contained in:
@@ -6,8 +6,7 @@ endif()
|
||||
|
||||
project(anm2ed CXX)
|
||||
|
||||
|
||||
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared)
|
||||
find_package(SDL3 REQUIRED)
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
@@ -28,22 +27,30 @@ if (WIN32)
|
||||
enable_language("RC")
|
||||
set (WIN32_RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/assets/win_icon.rc)
|
||||
endif()
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES} ${WIN32_RESOURCES})
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE include include/imgui include/tinyxml2 src)
|
||||
|
||||
if (NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "-g -O2 -std=c++23 -Wall -Wextra -pedantic -fmax-errors=1")
|
||||
set(CMAKE_CXX_FLAGS "-O2 -std=c++23 -Wall -Wextra -pedantic -fmax-errors=1")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "/std:c++latest /EHsc") # /std:c++latest is required to make MSVC grant access to all the latest C++ stuff (C++23 is listed as preview even on dev previews of MSVC....)
|
||||
set(CMAKE_CXX_FLAGS "/std:c++latest /EHsc")
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG -g")
|
||||
else()
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE m)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL GLEW::GLEW SDL3::SDL3)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL GLEW::GLEW SDL3::SDL3)
|
||||
|
||||
message("System: ${CMAKE_SYSTEM_NAME}")
|
||||
message("Project: ${PROJECT_NAME}")
|
||||
|
BIN
assets/atlas.png
BIN
assets/atlas.png
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
101
src/COMMON.h
101
src/COMMON.h
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
@@ -45,12 +43,9 @@ typedef double f64;
|
||||
|
||||
using namespace glm;
|
||||
|
||||
#define MIN(x, min) (x < min ? min : x)
|
||||
#define MAX(x, max) (x > max ? max : x)
|
||||
#define CLAMP(x, min, max) (MIN(MAX(x, max), min))
|
||||
#define ROUND_NEAREST_FLOAT(value, multiple) (roundf((value) / (multiple)) * (multiple))
|
||||
#define COLOR_FLOAT_TO_INT(x) (static_cast<int>((x) * 255.0f))
|
||||
#define COLOR_INT_TO_FLOAT(x) ((x) / 255.0f)
|
||||
#define ROUND_NEAREST_MULTIPLE(value, multiple) (roundf((value) / (multiple)) * (multiple))
|
||||
#define FLOAT_TO_U8(x) (static_cast<u8>((x) * 255.0f))
|
||||
#define U8_TO_FLOAT(x) ((x) / 255.0f)
|
||||
#define PERCENT_TO_UNIT(x) (x / 100.0f)
|
||||
#define TICK_DELAY 33.3f
|
||||
#define TICK_CATCH_UP_MAX (33.3f * 5)
|
||||
@@ -58,14 +53,14 @@ using namespace glm;
|
||||
#define TICK_RATE (SECOND / TICK_DELAY)
|
||||
#define ID_NONE -1
|
||||
#define INDEX_NONE -1
|
||||
#define LENGTH_NONE -1
|
||||
#define TIME_NONE -1.0f
|
||||
|
||||
#define UV_VERTICES(uvMin, uvMax) \
|
||||
{ \
|
||||
0, 0, uvMin.x, uvMin.y, \
|
||||
1, 0, uvMax.x, uvMin.y, \
|
||||
1, 1, uvMax.x, uvMax.y, \
|
||||
0, 1, uvMin.x, uvMax.y, \
|
||||
0, 1, uvMin.x, uvMax.y \
|
||||
}
|
||||
|
||||
static const f32 GL_VERTICES[] =
|
||||
@@ -76,7 +71,7 @@ static const f32 GL_VERTICES[] =
|
||||
0, 1
|
||||
};
|
||||
|
||||
static const f32 GL_UV_VERTICES[] =
|
||||
constexpr f32 GL_UV_VERTICES[] =
|
||||
{
|
||||
0, 0, 0.0f, 0.0f,
|
||||
1, 0, 1.0f, 0.0f,
|
||||
@@ -88,8 +83,9 @@ static const GLuint GL_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0};
|
||||
static const vec4 COLOR_RED = {1.0f, 0.0f, 0.0f, 1.0f};
|
||||
static const vec4 COLOR_GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
|
||||
static const vec4 COLOR_BLUE = {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
static const vec4 COLOR_PINK = {1.0f, 0.0f, 1.0f, 1.0f};
|
||||
static const vec4 COLOR_OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
static const vec4 COLOR_TRANSPARENT = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
static const vec4 COLOR_TRANSPARENT = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
static const vec3 COLOR_OFFSET_NONE = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
static inline void log_error(const std::string& string)
|
||||
@@ -102,6 +98,11 @@ static inline void log_info(const std::string& string)
|
||||
std::println("[INFO] {}", string);
|
||||
}
|
||||
|
||||
static inline void log_warning(const std::string& string)
|
||||
{
|
||||
std::println("[WARNING] {}", string);
|
||||
}
|
||||
|
||||
static inline bool string_to_bool(const std::string& string)
|
||||
{
|
||||
if (string == "1") return true;
|
||||
@@ -147,28 +148,11 @@ static inline s32 map_next_id_get(const std::map<s32, T>& map)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline s32 vector_next_id_get(const std::vector<T>& vec)
|
||||
static inline T* map_find(std::map<s32, T>& map, s32 id)
|
||||
{
|
||||
std::unordered_set<s32> usedIDs;
|
||||
for (const auto& item : vec)
|
||||
usedIDs.insert(item.id);
|
||||
|
||||
for (s32 i = 0; ; ++i)
|
||||
if (!usedIDs.contains(i))
|
||||
return i;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void vector_swap_by_id(std::vector<T>& vec, s32 idA, s32 idB)
|
||||
{
|
||||
if (idA == idB)
|
||||
return;
|
||||
|
||||
auto itA = std::find_if(vec.begin(), vec.end(), [=](const T& item) { return item.id == idA; });
|
||||
auto itB = std::find_if(vec.begin(), vec.end(), [=](const T& item) { return item.id == idB; });
|
||||
|
||||
if (itA != vec.end() && itB != vec.end())
|
||||
std::swap(*itA, *itB);
|
||||
if (auto it = map.find(id); it != map.end())
|
||||
return &it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Map, typename Key>
|
||||
@@ -219,6 +203,39 @@ static inline void map_insert_shift(std::map<int, T>& map, s32 index, const T& v
|
||||
map[insertIndex] = value;
|
||||
}
|
||||
|
||||
static inline mat4 quad_model_get(vec2 size, vec2 position, vec2 pivot, f32 rotation, vec2 scale)
|
||||
{
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 pivotScaled = pivot * scaleAbsolute;
|
||||
vec2 sizeScaled = size * scaleAbsolute;
|
||||
|
||||
mat4 model(1.0f);
|
||||
model = glm::translate(model, vec3(position - pivotScaled, 0.0f));
|
||||
model = glm::translate(model, vec3(pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(scaleSign, 1.0f));
|
||||
model = glm::rotate(model, glm::radians(rotation), vec3(0, 0, 1));
|
||||
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(sizeScaled, 1.0f));
|
||||
return model;
|
||||
}
|
||||
|
||||
static inline mat4 quad_parent_model_get(vec2 position, vec2 pivot, f32 rotation, vec2 scale)
|
||||
{
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
f32 handedness = (scaleSign.x * scaleSign.y) < 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
mat4 local(1.0f);
|
||||
local = glm::translate(local, vec3(pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleSign, 1.0f)); // mirror if needed
|
||||
local = glm::rotate(local, glm::radians(rotation) * handedness, vec3(0, 0, 1));
|
||||
local = glm::translate(local, vec3(-pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleAbsolute, 1.0f));
|
||||
|
||||
return glm::translate(mat4(1.0f), vec3(position, 0.0f)) * local;
|
||||
}
|
||||
|
||||
#define DEFINE_ENUM_TO_STRING_FUNCTION(function, array, count) \
|
||||
static inline std::string function(s32 index) \
|
||||
{ \
|
||||
@@ -230,3 +247,21 @@ static inline void map_insert_shift(std::map<int, T>& map, s32 index, const T& v
|
||||
{ \
|
||||
return static_cast<enumType>(string_to_enum(string, stringArray, count)); \
|
||||
};
|
||||
|
||||
|
||||
enum DataType
|
||||
{
|
||||
TYPE_INT,
|
||||
TYPE_BOOL,
|
||||
TYPE_FLOAT,
|
||||
TYPE_STRING,
|
||||
TYPE_IVEC2,
|
||||
TYPE_VEC2,
|
||||
TYPE_VEC4
|
||||
};
|
||||
|
||||
enum OriginType
|
||||
{
|
||||
ORIGIN_TOP_LEFT,
|
||||
ORIGIN_CENTER
|
||||
};
|
307
src/PACKED.h
307
src/PACKED.h
@@ -4,151 +4,151 @@
|
||||
|
||||
#include "COMMON.h"
|
||||
|
||||
const u32 TEXTURE_ATLAS_LENGTH = 1696;
|
||||
const u32 TEXTURE_ATLAS_LENGTH = 1698;
|
||||
const u8 TEXTURE_ATLAS[] =
|
||||
{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x68,
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0x0e, 0xcb, 0xf5, 0x55, 0x00, 0x00, 0x00,
|
||||
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b,
|
||||
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x06, 0x52, 0x49, 0x44,
|
||||
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x06, 0x54, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0xda, 0xed, 0x5d, 0x8b, 0x4e, 0xeb, 0x30, 0x0c, 0x65,
|
||||
0xd5, 0x3e, 0x14, 0xbe, 0x0c, 0xfe, 0x74, 0x97, 0x4a, 0x04, 0x05, 0x5f,
|
||||
0x3f, 0x8e, 0x1d, 0xa7, 0xe9, 0x56, 0x5b, 0x42, 0x6c, 0xb4, 0x69, 0x52,
|
||||
0xd5, 0x3e, 0x14, 0xbe, 0x0c, 0xfe, 0x74, 0x97, 0x48, 0x04, 0x05, 0x5f,
|
||||
0x3f, 0x8e, 0x1d, 0xa7, 0xed, 0x56, 0x5b, 0x42, 0x6c, 0xb4, 0x69, 0x52,
|
||||
0x1f, 0xbf, 0xf3, 0xe0, 0xed, 0xad, 0xe8, 0x9c, 0xf4, 0x20, 0xf4, 0xcc,
|
||||
0xef, 0x10, 0x69, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xee, 0xfb, 0xe7, 0x99,
|
||||
0x7d, 0xa9, 0x8c, 0x7f, 0x46, 0x20, 0x32, 0xc6, 0xee, 0x6d, 0xdb, 0x83,
|
||||
0xd5, 0xc0, 0x93, 0x80, 0x13, 0x01, 0xd5, 0x3a, 0xd4, 0xae, 0xf5, 0xd2,
|
||||
0x22, 0xd1, 0xcf, 0xc0, 0x86, 0x24, 0xd1, 0x62, 0xea, 0x03, 0xa4, 0x19,
|
||||
0x00, 0x34, 0xc6, 0x5b, 0xbc, 0x6a, 0xd7, 0xdd, 0x2a, 0x94, 0xf1, 0xe2,
|
||||
0x3b, 0x00, 0xfb, 0xcf, 0x08, 0x23, 0xb8, 0x71, 0x3c, 0x82, 0x34, 0xcb,
|
||||
0x04, 0x71, 0xc2, 0x47, 0x9f, 0xe9, 0x02, 0x20, 0x4b, 0xf2, 0xa8, 0x34,
|
||||
0xa3, 0xd2, 0x3f, 0x0a, 0x52, 0x54, 0x13, 0x22, 0x82, 0x82, 0x8e, 0xa7,
|
||||
0xb5, 0xbb, 0xf5, 0x2a, 0x71, 0xfb, 0x26, 0x4d, 0x5d, 0xda, 0x75, 0x7a,
|
||||
0x7f, 0xd4, 0x37, 0x70, 0xfd, 0x71, 0x7d, 0x5b, 0xf7, 0xa9, 0xaa, 0x1d,
|
||||
0xe8, 0x37, 0xd2, 0x7f, 0x7f, 0x2f, 0x32, 0x8e, 0xf6, 0x4c, 0x15, 0x00,
|
||||
0x8e, 0xf9, 0x33, 0x00, 0xb0, 0xfa, 0xb7, 0x18, 0x40, 0x4d, 0xc4, 0xe7,
|
||||
0xe7, 0x27, 0x7b, 0xdf, 0xc7, 0xc7, 0xc7, 0x9f, 0xef, 0x5f, 0x5f, 0x5f,
|
||||
0xb7, 0x15, 0x00, 0xec, 0xe3, 0x68, 0x7d, 0x6f, 0x88, 0x34, 0xa1, 0x12,
|
||||
0x33, 0x4a, 0x3d, 0x23, 0xdb, 0x67, 0xca, 0x34, 0x84, 0xf6, 0x36, 0x7d,
|
||||
0x3b, 0xfa, 0xdd, 0x6b, 0xfa, 0x50, 0x3f, 0x40, 0xc7, 0x2d, 0xf1, 0xad,
|
||||
0x07, 0xde, 0x34, 0x29, 0x9a, 0x59, 0xca, 0xd2, 0x80, 0x7d, 0xd0, 0x4d,
|
||||
0x6a, 0x2d, 0xad, 0xf0, 0x68, 0x82, 0x44, 0x9a, 0xe4, 0x6b, 0x63, 0xe9,
|
||||
0x25, 0x17, 0xd5, 0x96, 0xfe, 0x79, 0x5c, 0xfb, 0x8d, 0x76, 0xe4, 0x65,
|
||||
0xbe, 0x57, 0x32, 0xbd, 0x0c, 0xf1, 0x30, 0xdf, 0x7a, 0x4e, 0x7f, 0x9d,
|
||||
0x6a, 0x5b, 0x23, 0xca, 0xfc, 0xfe, 0xf3, 0x7e, 0xcd, 0x13, 0x19, 0xb5,
|
||||
0x3e, 0x1b, 0xa9, 0xe3, 0x43, 0x23, 0x84, 0xd1, 0x30, 0x54, 0x7a, 0x06,
|
||||
0x17, 0xef, 0x7b, 0xd5, 0x9e, 0xfb, 0xdd, 0xc7, 0xe7, 0xf4, 0x77, 0xf4,
|
||||
0xdd, 0x35, 0x1e, 0xa4, 0x65, 0x90, 0x2b, 0x12, 0xb1, 0x8c, 0xac, 0x5b,
|
||||
0x03, 0x43, 0x32, 0x53, 0xa7, 0x01, 0xe0, 0x0c, 0xa5, 0x88, 0x8c, 0x7e,
|
||||
0x10, 0xa6, 0x47, 0x92, 0x2e, 0xed, 0xbe, 0x74, 0xfe, 0xbc, 0x42, 0x31,
|
||||
0xce, 0xe3, 0x98, 0x8b, 0x8a, 0x8a, 0xb2, 0xcd, 0x21, 0xd2, 0x7e, 0x9b,
|
||||
0xa5, 0xf6, 0xd1, 0x88, 0xe6, 0x2c, 0xfd, 0xd3, 0x44, 0x2c, 0xc2, 0xfc,
|
||||
0x91, 0xf6, 0x87, 0x3b, 0x71, 0x24, 0x92, 0xd2, 0x98, 0xd9, 0xd7, 0xe1,
|
||||
0x81, 0x68, 0xec, 0x11, 0x79, 0x87, 0x51, 0x1e, 0x1c, 0xca, 0x7c, 0xcf,
|
||||
0x35, 0x4f, 0xba, 0x2f, 0x55, 0x48, 0xad, 0x4a, 0xeb, 0x0a, 0x6d, 0x0c,
|
||||
0x33, 0x3e, 0xa2, 0xc2, 0x54, 0xc2, 0xe8, 0x8f, 0x25, 0x0d, 0x5e, 0x09,
|
||||
0xd3, 0xfa, 0x1f, 0x8d, 0xea, 0xb2, 0x4c, 0xa8, 0x1b, 0x00, 0x54, 0x85,
|
||||
0xad, 0xf8, 0xd8, 0x62, 0xbe, 0x14, 0x47, 0x47, 0x01, 0x50, 0x27, 0x3a,
|
||||
0x04, 0x93, 0x20, 0xf5, 0xcf, 0x4d, 0x27, 0xd2, 0xbf, 0xa1, 0x02, 0x84,
|
||||
0x08, 0x1b, 0x5b, 0xfe, 0x95, 0x6a, 0x36, 0x5c, 0x9d, 0xc4, 0x6a, 0xd7,
|
||||
0x97, 0x86, 0xdb, 0x75, 0xee, 0x39, 0xfb, 0x33, 0x3c, 0x75, 0x7a, 0xad,
|
||||
0x3c, 0x6e, 0x55, 0x75, 0xa5, 0x62, 0x62, 0x2b, 0x25, 0x73, 0x45, 0xb3,
|
||||
0x56, 0x54, 0xeb, 0xcb, 0xcd, 0x5a, 0xe1, 0x50, 0x2b, 0xc2, 0xfd, 0x77,
|
||||
0x7f, 0x8f, 0x70, 0xff, 0x99, 0xce, 0x64, 0x49, 0x13, 0xce, 0x92, 0xf4,
|
||||
0x73, 0xce, 0x4f, 0x92, 0xd6, 0x11, 0x0d, 0xf0, 0xfa, 0x1d, 0x69, 0xf6,
|
||||
0x8a, 0x8b, 0x5e, 0xb8, 0x68, 0xe6, 0x91, 0x48, 0xac, 0xed, 0xa4, 0x1d,
|
||||
0xd1, 0x81, 0x71, 0xe0, 0xf4, 0x2a, 0xac, 0x31, 0x5f, 0xb2, 0xd7, 0x1e,
|
||||
0x00, 0x90, 0x32, 0x00, 0xe2, 0x90, 0x4f, 0x01, 0x00, 0x32, 0x01, 0x61,
|
||||
0x5d, 0xa7, 0x0c, 0x45, 0x0b, 0x77, 0x51, 0x0d, 0xb0, 0x6c, 0x2d, 0x12,
|
||||
0x71, 0x49, 0x8c, 0xb6, 0xfc, 0x9c, 0xd5, 0x7e, 0xa8, 0x6e, 0x24, 0xbd,
|
||||
0x84, 0x95, 0x54, 0x68, 0x8e, 0x56, 0x32, 0x4b, 0x5e, 0x27, 0xac, 0x45,
|
||||
0x31, 0x52, 0xff, 0x5a, 0x9e, 0x70, 0x16, 0x27, 0xbc, 0xd1, 0x09, 0x93,
|
||||
0xd6, 0xd1, 0x8d, 0x50, 0x1b, 0x04, 0xe7, 0x68, 0xb9, 0x89, 0x06, 0x6b,
|
||||
0x0a, 0xd0, 0x33, 0x09, 0x43, 0xfb, 0x6d, 0xe3, 0xd4, 0x9e, 0x45, 0x1d,
|
||||
0xa2, 0xd5, 0x47, 0xbb, 0x7f, 0x7f, 0xd6, 0xfe, 0xfc, 0x7e, 0xf2, 0x65,
|
||||
0xff, 0xdc, 0x3b, 0x52, 0xce, 0xd9, 0x7b, 0x26, 0xa8, 0xd4, 0x7b, 0xb5,
|
||||
0x50, 0xd4, 0x93, 0x41, 0x6a, 0x0e, 0xd9, 0x93, 0x88, 0x71, 0xa6, 0x8d,
|
||||
0x33, 0x8b, 0x52, 0x1f, 0x88, 0x4f, 0x3a, 0x73, 0x69, 0x7d, 0x59, 0x29,
|
||||
0x82, 0xfa, 0x18, 0xcd, 0x27, 0x79, 0x4a, 0x11, 0x88, 0x56, 0x3c, 0x6d,
|
||||
0x29, 0x62, 0x66, 0x31, 0x2e, 0x23, 0x93, 0xf5, 0x48, 0xfe, 0x28, 0xf3,
|
||||
0x5e, 0x65, 0x3e, 0xe5, 0xe5, 0xcb, 0xd1, 0x45, 0x67, 0xa4, 0xa8, 0x09,
|
||||
0xe1, 0x12, 0x1c, 0xed, 0x73, 0x76, 0xfb, 0xd9, 0xb5, 0xf7, 0x8c, 0x67,
|
||||
0x53, 0x33, 0x78, 0xf3, 0x76, 0x22, 0xd5, 0x5b, 0x46, 0x56, 0xcf, 0x8d,
|
||||
0xb6, 0x47, 0x6a, 0x42, 0x99, 0x00, 0x44, 0x9f, 0x4f, 0x85, 0x78, 0x0f,
|
||||
0x6b, 0x37, 0x2f, 0xc2, 0x59, 0xd1, 0xc0, 0xa8, 0x34, 0x65, 0x66, 0xd2,
|
||||
0xb3, 0x35, 0xa1, 0x59, 0x10, 0xd7, 0xc2, 0x2c, 0x69, 0xe5, 0x58, 0x46,
|
||||
0x48, 0x96, 0x0d, 0x80, 0xa7, 0xf6, 0x82, 0x2e, 0x3b, 0xc9, 0xdc, 0xe8,
|
||||
0xc1, 0xd5, 0xcb, 0x42, 0x21, 0x93, 0xa7, 0x3c, 0xe1, 0x01, 0x2f, 0x23,
|
||||
0xd2, 0x18, 0xdd, 0x1b, 0x30, 0x63, 0x8f, 0x01, 0xb7, 0x27, 0x82, 0x15,
|
||||
0x80, 0x68, 0xb6, 0x8b, 0x30, 0x10, 0xd1, 0x80, 0x8c, 0x49, 0xef, 0x15,
|
||||
0x00, 0x44, 0x98, 0xaf, 0xee, 0x8e, 0xf1, 0xee, 0x46, 0xf1, 0xdc, 0x4b,
|
||||
0xd5, 0x70, 0x86, 0x0f, 0xf0, 0x26, 0x69, 0x52, 0x35, 0x77, 0xf4, 0xdd,
|
||||
0x5d, 0xcc, 0x47, 0x6a, 0xe7, 0x11, 0x0d, 0xd0, 0x26, 0x43, 0x66, 0x85,
|
||||
0x8e, 0xd1, 0xad, 0x47, 0x99, 0x5b, 0x96, 0xdc, 0xcc, 0xb7, 0x4c, 0x90,
|
||||
0xb6, 0xf7, 0x09, 0x51, 0x5f, 0xd4, 0x84, 0x78, 0x19, 0xec, 0xda, 0x81,
|
||||
0x98, 0x08, 0x80, 0x37, 0x87, 0x82, 0xf6, 0xb9, 0x69, 0xd5, 0x4a, 0x24,
|
||||
0x9a, 0x88, 0xda, 0xc8, 0x55, 0xa9, 0x7d, 0x14, 0x00, 0x14, 0x20, 0x17,
|
||||
0xf3, 0x11, 0x67, 0x19, 0xdd, 0x25, 0x99, 0x15, 0x57, 0x67, 0x56, 0x17,
|
||||
0x47, 0x7c, 0x80, 0xc7, 0x3f, 0xa0, 0xcc, 0xbf, 0x69, 0x8c, 0x90, 0x36,
|
||||
0x9c, 0x69, 0x9b, 0xf9, 0xd0, 0x89, 0x87, 0x3e, 0xfb, 0xb5, 0x32, 0xe1,
|
||||
0xc8, 0xf3, 0x2d, 0x60, 0xd1, 0x77, 0x40, 0x33, 0x5f, 0x8e, 0x77, 0x08,
|
||||
0x70, 0x5b, 0xa4, 0x51, 0x76, 0xd6, 0x69, 0xf5, 0xdb, 0x66, 0xe5, 0xa4,
|
||||
0xef, 0x67, 0xa8, 0x9d, 0xf5, 0x33, 0x76, 0x9e, 0xb1, 0x6d, 0xd2, 0xcb,
|
||||
0x8e, 0x48, 0x17, 0x52, 0x60, 0xe3, 0x24, 0x30, 0x52, 0x7c, 0xf3, 0x92,
|
||||
0xb4, 0x7b, 0x71, 0xff, 0x5b, 0x64, 0x47, 0xa6, 0x26, 0x28, 0x45, 0x45,
|
||||
0xd7, 0xa2, 0x88, 0xb6, 0x6e, 0xcf, 0xf4, 0x82, 0xd6, 0x1a, 0xd0, 0x91,
|
||||
0xd2, 0x30, 0xd2, 0xef, 0x0a, 0x80, 0x7e, 0x07, 0x10, 0x5d, 0x1d, 0xcc,
|
||||
0x9d, 0x14, 0xe2, 0x79, 0x16, 0x77, 0x0e, 0xcf, 0x08, 0x33, 0xb4, 0xb5,
|
||||
0x3d, 0x56, 0xff, 0xa3, 0x0c, 0x0e, 0x8d, 0x7d, 0xe4, 0xc5, 0xb9, 0x75,
|
||||
0xa6, 0x68, 0x92, 0xc6, 0xad, 0x4f, 0x8d, 0x68, 0x8a, 0x96, 0x34, 0x66,
|
||||
0xd6, 0xbd, 0x34, 0x06, 0x87, 0xf3, 0x18, 0x74, 0x6d, 0xbf, 0x87, 0x19,
|
||||
0xd6, 0x20, 0xa3, 0x4c, 0x97, 0x18, 0xcf, 0xad, 0x6a, 0xf3, 0x08, 0x41,
|
||||
0x64, 0xee, 0xc3, 0x03, 0xc0, 0xdd, 0x52, 0x55, 0xee, 0xe4, 0x11, 0xe4,
|
||||
0x58, 0x80, 0x3e, 0xc1, 0xfa, 0xbe, 0xf7, 0x8f, 0xca, 0x5b, 0xe1, 0x5e,
|
||||
0x24, 0x94, 0x6b, 0xcb, 0xc1, 0xe9, 0x12, 0x78, 0xc9, 0xee, 0x6b, 0x63,
|
||||
0x88, 0x1e, 0x54, 0x22, 0xdd, 0xeb, 0x3e, 0xff, 0xc2, 0xda, 0x58, 0x81,
|
||||
0xda, 0x43, 0xcd, 0x27, 0x58, 0x7d, 0x5a, 0xdf, 0x25, 0xc9, 0x97, 0xc6,
|
||||
0x8e, 0xae, 0x09, 0x8a, 0xbc, 0x6b, 0xaa, 0x0f, 0xe0, 0x54, 0x35, 0x83,
|
||||
0xf9, 0xd4, 0x27, 0x64, 0x02, 0xe0, 0x3d, 0xad, 0xcb, 0x6b, 0x2e, 0xbd,
|
||||
0x66, 0x2b, 0x2d, 0xcc, 0xcb, 0x60, 0x3e, 0x8d, 0x3a, 0xb4, 0x4d, 0x76,
|
||||
0xd1, 0x10, 0x12, 0x29, 0x8d, 0x23, 0xa1, 0xe4, 0xc8, 0x7c, 0x72, 0x38,
|
||||
0x7b, 0xa6, 0x36, 0x94, 0x2b, 0xc6, 0x35, 0x7b, 0x89, 0x9c, 0x30, 0x15,
|
||||
0x5d, 0xb6, 0xe2, 0x7d, 0x39, 0xba, 0xe5, 0x47, 0x3b, 0xbb, 0xa8, 0xad,
|
||||
0x76, 0xf6, 0xd8, 0x74, 0xce, 0x07, 0x4a, 0x6d, 0x91, 0x62, 0xa1, 0x5a,
|
||||
0xac, 0xd3, 0x54, 0x0f, 0x65, 0x8e, 0x25, 0xf9, 0x23, 0x89, 0x11, 0xbd,
|
||||
0x66, 0x1d, 0x37, 0xa3, 0x6d, 0xb7, 0x1a, 0x29, 0x31, 0x7b, 0x35, 0x07,
|
||||
0xb9, 0xbe, 0x59, 0x92, 0x8d, 0x46, 0x3c, 0x9c, 0x84, 0x66, 0x2d, 0xb8,
|
||||
0xca, 0x2a, 0x86, 0x79, 0xc6, 0x72, 0xd4, 0x91, 0x6d, 0x77, 0x6a, 0x6e,
|
||||
0x34, 0x55, 0xf7, 0x4a, 0xcf, 0x51, 0xcc, 0xe7, 0xfa, 0xe9, 0x77, 0x28,
|
||||
0x4a, 0x87, 0xf8, 0x21, 0x1a, 0x37, 0xfb, 0x1d, 0xee, 0x9c, 0xcd, 0xef,
|
||||
0x6d, 0x67, 0x1b, 0xcc, 0x0e, 0x44, 0xaf, 0x0d, 0x54, 0x33, 0xe8, 0xae,
|
||||
0x95, 0x68, 0x2c, 0x9f, 0xe1, 0x23, 0x22, 0x4c, 0xa7, 0xe0, 0x69, 0xe7,
|
||||
0xc3, 0x4d, 0x71, 0xc2, 0xda, 0xcb, 0xf6, 0xcc, 0x8f, 0x9a, 0xa4, 0x57,
|
||||
0xaf, 0x82, 0x0e, 0x39, 0xe1, 0xa2, 0x75, 0x74, 0xcb, 0x88, 0x6d, 0x47,
|
||||
0x34, 0xe2, 0x2c, 0x1a, 0xb5, 0xe2, 0x9c, 0xd4, 0xdf, 0x28, 0xa8, 0x68,
|
||||
0x1d, 0xdd, 0xa5, 0xc2, 0x15, 0xea, 0xec, 0x8a, 0x4a, 0x03, 0x0a, 0x80,
|
||||
0x55, 0xfe, 0xa3, 0x00, 0x28, 0x2a, 0x00, 0x0a, 0x80, 0xa2, 0x02, 0xa0,
|
||||
0x00, 0x28, 0x2a, 0x00, 0x0a, 0x80, 0xa2, 0x78, 0x26, 0x7c, 0x65, 0xd2,
|
||||
0xf6, 0xac, 0x1d, 0x51, 0x13, 0xba, 0x17, 0xe3, 0xed, 0x7b, 0x66, 0x02,
|
||||
0xb1, 0x5d, 0x9d, 0xf9, 0xdc, 0x34, 0x26, 0xfd, 0xdb, 0xcc, 0x63, 0x10,
|
||||
0x2e, 0xed, 0x03, 0x00, 0xc9, 0x9e, 0x6e, 0x82, 0xb6, 0xab, 0x4a, 0x3f,
|
||||
0x62, 0x56, 0xf6, 0x5b, 0x46, 0xff, 0x55, 0x57, 0x01, 0x50, 0x51, 0xd0,
|
||||
0x7a, 0x67, 0xea, 0x6d, 0x37, 0xb2, 0x09, 0xdc, 0x69, 0xe2, 0x4a, 0x03,
|
||||
0x2a, 0x11, 0x2b, 0x13, 0xf4, 0xf2, 0x91, 0x0c, 0xe4, 0x84, 0xb5, 0x49,
|
||||
0xf9, 0x99, 0xf9, 0x40, 0x69, 0x40, 0x99, 0xa0, 0x35, 0x1a, 0x03, 0x66,
|
||||
0xc2, 0xd3, 0xb3, 0xe1, 0x4b, 0x6b, 0x00, 0x00, 0xc2, 0xf4, 0x83, 0x00,
|
||||
0x2f, 0x59, 0x0b, 0xea, 0xd7, 0xc0, 0x22, 0x07, 0x48, 0x1d, 0xb2, 0x3a,
|
||||
0xba, 0x4c, 0xd1, 0xb8, 0x83, 0x2f, 0x00, 0x92, 0x80, 0xa8, 0xa5, 0x89,
|
||||
0x15, 0x05, 0x15, 0x15, 0x00, 0x05, 0x40, 0x51, 0x01, 0x70, 0x15, 0xf2,
|
||||
0x1e, 0x5a, 0x4d, 0x8f, 0xa1, 0x79, 0x95, 0xa4, 0x6c, 0xe9, 0x7f, 0xbc,
|
||||
0x88, 0xfe, 0x3f, 0xdf, 0x02, 0xe0, 0x60, 0x10, 0xac, 0x4d, 0xd3, 0x91,
|
||||
0x3e, 0xaf, 0x0c, 0xc0, 0x1f, 0x1f, 0xd0, 0xfe, 0x89, 0x99, 0x44, 0x47,
|
||||
0x6d, 0xdd, 0xbc, 0xb4, 0x13, 0x96, 0x40, 0x28, 0xe6, 0x1f, 0x18, 0x05,
|
||||
0x51, 0x10, 0x8a, 0xf9, 0xf3, 0x48, 0xac, 0x05, 0xfd, 0x30, 0xfc, 0xd1,
|
||||
0x7d, 0x7e, 0x69, 0x5a, 0xb5, 0x71, 0xfa, 0x1f, 0xcc, 0xd3, 0x69, 0xcc,
|
||||
0x40, 0x9f, 0x7b, 0x52, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
|
||||
0xae, 0x42, 0x60, 0x82
|
||||
0xef, 0x10, 0x69, 0xfb, 0xfe, 0xfe, 0xfe, 0xfb, 0xee, 0xed, 0xf3, 0xca,
|
||||
0xbe, 0x54, 0xc6, 0x3f, 0x23, 0x10, 0x19, 0x63, 0xf7, 0xb6, 0x1d, 0xc1,
|
||||
0xea, 0xe0, 0x49, 0xc0, 0x89, 0x80, 0x6a, 0x1d, 0x6a, 0xd7, 0x46, 0x69,
|
||||
0x91, 0xe8, 0x67, 0x60, 0x53, 0x92, 0x68, 0x31, 0xf5, 0x01, 0xd2, 0x0a,
|
||||
0x00, 0x3a, 0xe3, 0x2d, 0x5e, 0xf5, 0xeb, 0x6e, 0x15, 0xca, 0x78, 0xf1,
|
||||
0x06, 0x40, 0xfb, 0x99, 0x61, 0x04, 0x37, 0x8e, 0x47, 0x90, 0x56, 0x99,
|
||||
0x20, 0x4e, 0xf8, 0xe8, 0x33, 0x5d, 0x00, 0x64, 0x49, 0x1e, 0x95, 0x66,
|
||||
0x54, 0xfa, 0x67, 0x41, 0x8a, 0x6a, 0x42, 0x44, 0x50, 0xd0, 0xf1, 0xf4,
|
||||
0x76, 0xb7, 0x51, 0x25, 0x6e, 0xdf, 0xa4, 0xa9, 0x4b, 0xbf, 0x4e, 0xef,
|
||||
0x8f, 0xfa, 0x06, 0xae, 0x3f, 0xae, 0x6f, 0xeb, 0x3e, 0x55, 0xb5, 0x03,
|
||||
0xfd, 0x46, 0xfa, 0x1f, 0xef, 0x45, 0xc6, 0xd1, 0x9f, 0xa9, 0x02, 0xc0,
|
||||
0x31, 0x7f, 0x05, 0x00, 0x56, 0xff, 0x16, 0x03, 0xa8, 0x89, 0xf8, 0xfc,
|
||||
0xfc, 0x64, 0xef, 0xfb, 0xf8, 0xf8, 0xf8, 0xf3, 0xfd, 0xeb, 0xeb, 0xeb,
|
||||
0x76, 0x04, 0x00, 0x6d, 0x1c, 0xbd, 0xef, 0x0d, 0x91, 0x26, 0x54, 0x62,
|
||||
0x66, 0x69, 0x64, 0x64, 0xff, 0x4c, 0x99, 0x86, 0x50, 0x6b, 0x33, 0xb6,
|
||||
0xa3, 0xdf, 0xbd, 0xa6, 0x0f, 0xf5, 0x03, 0x74, 0xdc, 0x12, 0xdf, 0x46,
|
||||
0xe0, 0x4d, 0x93, 0xa2, 0x99, 0xa5, 0x2c, 0x0d, 0x68, 0x83, 0xee, 0x52,
|
||||
0x6b, 0x69, 0x85, 0x47, 0x13, 0x24, 0xd2, 0x24, 0x5f, 0x1b, 0xcb, 0x28,
|
||||
0xb9, 0xa8, 0xb6, 0x8c, 0xcf, 0xe3, 0xda, 0x6f, 0xb4, 0x23, 0x2f, 0xf3,
|
||||
0xbd, 0x92, 0xe9, 0x65, 0x88, 0x87, 0xf9, 0xd6, 0x73, 0xc6, 0xeb, 0x54,
|
||||
0xdb, 0x3a, 0x51, 0xe6, 0x8f, 0x9f, 0xdb, 0x35, 0x4f, 0x64, 0xd4, 0xfb,
|
||||
0xec, 0xa4, 0x8e, 0x0f, 0x8d, 0x10, 0x66, 0xc3, 0x50, 0xe9, 0x19, 0x5c,
|
||||
0xbc, 0xef, 0x55, 0x7b, 0xee, 0xf7, 0x18, 0x9f, 0xd3, 0xdf, 0xd1, 0x77,
|
||||
0xd7, 0x78, 0x90, 0x96, 0x41, 0x1e, 0x91, 0x88, 0x65, 0x64, 0xdd, 0x1a,
|
||||
0x18, 0x92, 0x99, 0x3a, 0x0d, 0x00, 0x67, 0x28, 0x45, 0x64, 0xf4, 0x83,
|
||||
0x30, 0x3d, 0x92, 0x74, 0x69, 0xf7, 0xa5, 0xf3, 0xe7, 0x15, 0x8a, 0x71,
|
||||
0x1e, 0xc7, 0x5c, 0x54, 0x54, 0x94, 0x6d, 0x0e, 0x91, 0xf6, 0xdb, 0x2a,
|
||||
0xb5, 0x8f, 0x46, 0x34, 0x67, 0xe9, 0x9f, 0x26, 0x62, 0x11, 0xe6, 0xcf,
|
||||
0xb4, 0xdf, 0xdd, 0x89, 0x23, 0x91, 0x94, 0xc6, 0xcc, 0xb1, 0x0e, 0x0f,
|
||||
0x44, 0x63, 0x8f, 0xc8, 0x3b, 0xcc, 0xf2, 0x60, 0x57, 0xe6, 0x7b, 0xae,
|
||||
0x79, 0xd2, 0x7d, 0xa9, 0x42, 0x6a, 0x55, 0x5a, 0x8f, 0xd0, 0xc6, 0x30,
|
||||
0xe3, 0x23, 0x2a, 0x4c, 0x25, 0x8c, 0xfe, 0x58, 0xd2, 0xe0, 0x95, 0x30,
|
||||
0xad, 0xff, 0xd9, 0xa8, 0x2e, 0xcb, 0x84, 0xba, 0x01, 0x40, 0x55, 0xd8,
|
||||
0x8a, 0x8f, 0x2d, 0xe6, 0x4b, 0x71, 0x74, 0x14, 0x00, 0x75, 0xa2, 0x43,
|
||||
0x30, 0x09, 0x52, 0xff, 0xdc, 0x74, 0x22, 0xfd, 0x1b, 0x2a, 0x40, 0x88,
|
||||
0xb0, 0xb1, 0xe5, 0x5f, 0xa9, 0x66, 0xc3, 0xd5, 0x49, 0xac, 0x76, 0x63,
|
||||
0x69, 0xb8, 0x5f, 0xe7, 0x9e, 0xd3, 0x9e, 0xe1, 0xa9, 0xd3, 0x6b, 0xe5,
|
||||
0x71, 0xab, 0xaa, 0x2b, 0x15, 0x13, 0x7b, 0x29, 0x99, 0x2b, 0x9a, 0xf5,
|
||||
0xa2, 0xda, 0x58, 0x6e, 0xd6, 0x0a, 0x87, 0x5a, 0x11, 0xee, 0xbf, 0xfb,
|
||||
0x47, 0x84, 0xc7, 0xcf, 0x74, 0x26, 0x4b, 0x9a, 0x70, 0x96, 0xa4, 0x9f,
|
||||
0x73, 0x7e, 0x92, 0xb4, 0xce, 0x68, 0x80, 0xd7, 0xef, 0x48, 0xb3, 0x57,
|
||||
0x5c, 0xf4, 0xc2, 0x45, 0x33, 0x8f, 0x44, 0x62, 0x6d, 0x27, 0xed, 0x88,
|
||||
0x0e, 0x8c, 0x03, 0x67, 0x54, 0x61, 0x8d, 0xf9, 0x92, 0xbd, 0xf6, 0x00,
|
||||
0x80, 0x94, 0x01, 0x10, 0x87, 0x7c, 0x0a, 0x00, 0x90, 0x09, 0x08, 0xeb,
|
||||
0x3a, 0x65, 0x28, 0x5a, 0xb8, 0x8b, 0x6a, 0x80, 0x65, 0x6b, 0x91, 0x88,
|
||||
0x4b, 0x62, 0xb4, 0xe5, 0xe7, 0xac, 0xf6, 0x53, 0x75, 0x23, 0xe9, 0x25,
|
||||
0xac, 0xa4, 0x42, 0x73, 0xb4, 0x92, 0x59, 0xf2, 0x3a, 0x61, 0x2d, 0x8a,
|
||||
0x91, 0xfa, 0xd7, 0xf2, 0x84, 0xb3, 0x38, 0xe1, 0x8d, 0x4e, 0x98, 0xf4,
|
||||
0x8e, 0x6e, 0x84, 0xfa, 0x20, 0x38, 0x47, 0xcb, 0x4d, 0x34, 0x58, 0x53,
|
||||
0x80, 0x9e, 0x49, 0x18, 0xda, 0x6f, 0x1f, 0xa7, 0xf6, 0x2c, 0xea, 0x10,
|
||||
0xad, 0x3e, 0xfa, 0xfd, 0xed, 0x59, 0xed, 0xf9, 0xe3, 0xe4, 0x4b, 0xfb,
|
||||
0x3c, 0x3a, 0x52, 0xce, 0xd9, 0x7b, 0x26, 0xa8, 0xd4, 0x7b, 0xb5, 0x50,
|
||||
0xd4, 0x93, 0x41, 0x6a, 0x0e, 0xd9, 0x93, 0x88, 0x71, 0xa6, 0x8d, 0x33,
|
||||
0x8b, 0x52, 0x1f, 0x88, 0x4f, 0x3a, 0x73, 0x69, 0xfd, 0xb0, 0x52, 0x04,
|
||||
0xf5, 0x31, 0x9a, 0x4f, 0xf2, 0x94, 0x22, 0x10, 0xad, 0x78, 0xda, 0x52,
|
||||
0xc4, 0xca, 0x62, 0x5c, 0x46, 0x26, 0xeb, 0x91, 0xfc, 0x59, 0xe6, 0xbd,
|
||||
0xca, 0x7c, 0xca, 0xcb, 0x97, 0xa3, 0x8b, 0xce, 0x48, 0x51, 0x13, 0xc2,
|
||||
0x25, 0x38, 0xda, 0xe7, 0xec, 0xf6, 0xab, 0x6b, 0xef, 0x19, 0xcf, 0xa6,
|
||||
0x66, 0xf0, 0xe6, 0xed, 0x44, 0xaa, 0xb7, 0xcc, 0xac, 0x9e, 0x9b, 0x6d,
|
||||
0x8f, 0xd4, 0x84, 0x32, 0x01, 0x88, 0x3e, 0x9f, 0x0a, 0x71, 0x0b, 0x6b,
|
||||
0x37, 0x2f, 0xc2, 0x59, 0xd1, 0xc0, 0xac, 0x34, 0x65, 0x66, 0xd2, 0xab,
|
||||
0x35, 0xa1, 0x5b, 0x10, 0xd7, 0xc2, 0x2c, 0x69, 0xe5, 0x58, 0x46, 0x48,
|
||||
0x96, 0x0d, 0x80, 0xa7, 0xf6, 0x82, 0x2e, 0x3b, 0xc9, 0xdc, 0xe8, 0xc1,
|
||||
0xd5, 0xcb, 0x42, 0x21, 0x93, 0xa7, 0x3c, 0xe1, 0x01, 0x2f, 0x23, 0xd2,
|
||||
0x98, 0xdd, 0x1b, 0xb0, 0x62, 0x8f, 0x01, 0xb7, 0x27, 0x82, 0x15, 0x80,
|
||||
0x68, 0xb6, 0x8b, 0x30, 0x10, 0xd1, 0x80, 0x8c, 0x49, 0xef, 0x23, 0x00,
|
||||
0x88, 0x30, 0x5f, 0xdd, 0x1d, 0xe3, 0xdd, 0x8d, 0xe2, 0xb9, 0x97, 0xaa,
|
||||
0xe1, 0x0a, 0x1f, 0xe0, 0x4d, 0xd2, 0xa4, 0x6a, 0xee, 0xec, 0xbb, 0xbb,
|
||||
0x98, 0x8f, 0xd4, 0xce, 0x23, 0x1a, 0xa0, 0x4d, 0x86, 0xac, 0x0a, 0x1d,
|
||||
0xa3, 0x5b, 0x8f, 0x32, 0xb7, 0x2c, 0xb9, 0x99, 0x6f, 0x99, 0x20, 0x6d,
|
||||
0xef, 0x13, 0xa2, 0xbe, 0xa8, 0x09, 0xf1, 0x32, 0xd8, 0xb5, 0x03, 0x31,
|
||||
0x11, 0x00, 0x6f, 0x0e, 0x05, 0xed, 0x73, 0xd3, 0xaa, 0x95, 0x48, 0x34,
|
||||
0x11, 0xb5, 0x91, 0x47, 0xa5, 0xf6, 0x51, 0x00, 0x50, 0x80, 0x5c, 0xcc,
|
||||
0x47, 0x9c, 0x65, 0x74, 0x97, 0x64, 0x56, 0x5c, 0x9d, 0x59, 0x5d, 0x9c,
|
||||
0xf1, 0x01, 0x1e, 0xff, 0x80, 0x32, 0xff, 0xa6, 0x31, 0x42, 0xda, 0x70,
|
||||
0xa6, 0x6d, 0xe6, 0x43, 0x27, 0x1e, 0xc6, 0xec, 0xd7, 0xca, 0x84, 0x23,
|
||||
0xcf, 0xb7, 0x80, 0x45, 0xdf, 0x01, 0xcd, 0x7c, 0x39, 0xde, 0x21, 0xc0,
|
||||
0x6d, 0x91, 0x46, 0xd9, 0x59, 0xa7, 0xd5, 0x6f, 0x9f, 0x95, 0x93, 0xbe,
|
||||
0x9f, 0xa1, 0x76, 0x36, 0xce, 0xd8, 0x79, 0xc6, 0xb6, 0x49, 0x2f, 0x3b,
|
||||
0x23, 0x5d, 0x48, 0x81, 0x8d, 0x93, 0xc0, 0x48, 0xf1, 0xcd, 0x4b, 0xd2,
|
||||
0xee, 0xc5, 0xf6, 0xb7, 0xc8, 0x8e, 0x4c, 0x4d, 0x50, 0x8a, 0x8a, 0xae,
|
||||
0x45, 0x11, 0x6d, 0xdd, 0x9e, 0xe9, 0x05, 0xad, 0x35, 0xa0, 0x33, 0xa5,
|
||||
0x61, 0xa4, 0xdf, 0x23, 0x00, 0xfa, 0x1d, 0x40, 0x74, 0x75, 0x30, 0x77,
|
||||
0x52, 0x88, 0xe7, 0x59, 0xdc, 0x39, 0x3c, 0x33, 0xcc, 0xd0, 0xd6, 0xf6,
|
||||
0x58, 0xfd, 0xcf, 0x32, 0x38, 0x34, 0xf6, 0x99, 0x17, 0xe7, 0xd6, 0x99,
|
||||
0xa2, 0x49, 0x1a, 0xb7, 0x3e, 0x35, 0xa2, 0x29, 0x5a, 0xd2, 0x98, 0x59,
|
||||
0xf7, 0xd2, 0x18, 0x1c, 0xce, 0x63, 0xd0, 0xb5, 0xfd, 0x1e, 0x66, 0x58,
|
||||
0x83, 0x8c, 0x32, 0x5d, 0x62, 0x3c, 0xb7, 0xaa, 0xcd, 0x23, 0x04, 0x91,
|
||||
0xb9, 0x0f, 0x0f, 0x00, 0x77, 0x4b, 0x55, 0xb9, 0x93, 0x47, 0x90, 0x63,
|
||||
0x01, 0xc6, 0x04, 0xeb, 0xfb, 0xde, 0x3f, 0x2a, 0x6f, 0x85, 0x7b, 0x91,
|
||||
0x50, 0xae, 0x2f, 0x07, 0xa7, 0x4b, 0xe0, 0x25, 0xbb, 0xaf, 0x8d, 0x21,
|
||||
0x7a, 0x50, 0x89, 0x74, 0xaf, 0xfb, 0xfc, 0x0b, 0x6b, 0x63, 0x05, 0x6a,
|
||||
0x0f, 0x35, 0x9f, 0x60, 0xf5, 0x69, 0x7d, 0x97, 0x24, 0x5f, 0x1a, 0x3b,
|
||||
0xba, 0x26, 0x28, 0xf2, 0xae, 0xa9, 0x3e, 0x80, 0x53, 0xd5, 0x0c, 0xe6,
|
||||
0x53, 0x9f, 0x90, 0x09, 0x80, 0xf7, 0xb4, 0x2e, 0xaf, 0xb9, 0xf4, 0x9a,
|
||||
0xad, 0xb4, 0x30, 0x2f, 0x83, 0xf9, 0x34, 0xea, 0xd0, 0x36, 0xd9, 0x45,
|
||||
0x43, 0x48, 0xa4, 0x34, 0x8e, 0x84, 0x92, 0x33, 0xf3, 0xc9, 0xe1, 0xec,
|
||||
0x99, 0xda, 0x50, 0xae, 0x18, 0xd7, 0xed, 0x25, 0x72, 0xc2, 0x54, 0x74,
|
||||
0xd9, 0x8a, 0xf7, 0xe5, 0xe8, 0x96, 0x1f, 0xed, 0xec, 0xa2, 0xbe, 0xda,
|
||||
0xd9, 0x63, 0xd3, 0x39, 0x1f, 0x28, 0xb5, 0x45, 0x8a, 0x85, 0x6a, 0xb1,
|
||||
0x4e, 0x53, 0x3d, 0x94, 0x39, 0x96, 0xe4, 0xcf, 0x24, 0x46, 0xf4, 0x9a,
|
||||
0x75, 0xdc, 0x8c, 0xb6, 0xdd, 0x6a, 0xa6, 0xc4, 0xec, 0xd5, 0x1c, 0xe4,
|
||||
0xfa, 0x66, 0x49, 0x36, 0x1a, 0xf1, 0x70, 0x12, 0x9a, 0xb5, 0xe0, 0x2a,
|
||||
0xab, 0x18, 0xe6, 0x19, 0xcb, 0x5e, 0x47, 0xb6, 0xdd, 0xa9, 0xb9, 0xd1,
|
||||
0x54, 0xdd, 0x2b, 0x3d, 0x7b, 0x31, 0x9f, 0xeb, 0x67, 0xdc, 0xa1, 0x28,
|
||||
0x1d, 0xe2, 0x87, 0x68, 0xdc, 0xea, 0x77, 0xb8, 0x73, 0x36, 0x7f, 0xb4,
|
||||
0x9d, 0x7d, 0x30, 0x0d, 0x88, 0x51, 0x1b, 0xa8, 0x66, 0xd0, 0x5d, 0x2b,
|
||||
0xd1, 0x58, 0x3e, 0xc3, 0x47, 0x44, 0x98, 0x4e, 0xc1, 0xd3, 0xce, 0x87,
|
||||
0x5b, 0xe2, 0x84, 0xb5, 0x97, 0x1d, 0x99, 0x1f, 0x35, 0x49, 0xaf, 0x5e,
|
||||
0x05, 0x9d, 0x72, 0xc2, 0x45, 0xc7, 0xd1, 0xed, 0x0c, 0x27, 0x4a, 0x9d,
|
||||
0x41, 0xa3, 0x8e, 0x38, 0x27, 0x55, 0xad, 0x05, 0xed, 0xc1, 0xc0, 0x3a,
|
||||
0x4e, 0xec, 0x07, 0x80, 0xa8, 0xc3, 0x9a, 0x9d, 0x43, 0x2d, 0x7a, 0xb2,
|
||||
0x19, 0xb1, 0x02, 0xe0, 0x45, 0xed, 0x7f, 0x69, 0x40, 0x01, 0x50, 0x54,
|
||||
0x00, 0x14, 0x00, 0x45, 0x05, 0x40, 0x01, 0x50, 0x54, 0x00, 0x5c, 0x31,
|
||||
0x13, 0xbe, 0x32, 0x69, 0x7b, 0xd6, 0xf6, 0xa8, 0x09, 0xdd, 0x8b, 0xf1,
|
||||
0xf6, 0x3d, 0x2b, 0x81, 0xd8, 0xae, 0xce, 0x7c, 0x6e, 0x1a, 0x93, 0xfe,
|
||||
0x6d, 0xe5, 0x31, 0x08, 0x97, 0xf6, 0x01, 0x80, 0x64, 0x2f, 0x37, 0x41,
|
||||
0xdb, 0x55, 0xa5, 0x1f, 0x31, 0x2b, 0xed, 0x96, 0xd9, 0x7f, 0xd5, 0x55,
|
||||
0x00, 0x54, 0x14, 0x74, 0xbc, 0x33, 0xf5, 0xb6, 0x9b, 0xd9, 0x04, 0xee,
|
||||
0x34, 0x71, 0xa5, 0x01, 0x95, 0x88, 0x95, 0x09, 0x7a, 0xf9, 0x48, 0x06,
|
||||
0x72, 0xc2, 0xda, 0xa4, 0xfc, 0xca, 0x7c, 0xa0, 0x34, 0xa0, 0x4c, 0xd0,
|
||||
0x31, 0x1a, 0x03, 0x66, 0xc2, 0xcb, 0xb3, 0xe1, 0x4b, 0x6b, 0x00, 0x00,
|
||||
0xc2, 0xf2, 0x65, 0x33, 0x97, 0xac, 0x05, 0x8d, 0x6b, 0x60, 0x91, 0x03,
|
||||
0xa4, 0x76, 0x59, 0x1d, 0x5d, 0xa6, 0x68, 0xde, 0xc1, 0x17, 0x00, 0x49,
|
||||
0x40, 0xec, 0xb9, 0x34, 0xb1, 0xa2, 0xa0, 0x8a, 0x82, 0x0a, 0x80, 0xa2,
|
||||
0x02, 0xa0, 0x00, 0x28, 0x3a, 0x0a, 0x80, 0xfe, 0x5f, 0x83, 0xbc, 0xb4,
|
||||
0xd7, 0x1e, 0xaa, 0x4b, 0x68, 0x80, 0x17, 0x84, 0x62, 0xfe, 0x02, 0x13,
|
||||
0x84, 0x82, 0x90, 0xcd, 0xfc, 0xab, 0xef, 0x92, 0xf9, 0xe3, 0x03, 0x2c,
|
||||
0x10, 0x4a, 0xf2, 0x77, 0x70, 0xc2, 0x12, 0x08, 0xc5, 0xfc, 0x1d, 0xa3,
|
||||
0x20, 0x0a, 0x42, 0x31, 0x7f, 0x1d, 0x89, 0xb5, 0xa0, 0x1f, 0x86, 0x3f,
|
||||
0x86, 0xcf, 0x2f, 0x6d, 0xc7, 0x8f, 0xda, 0x38, 0xfd, 0x0f, 0xc3, 0x64,
|
||||
0xcf, 0x81, 0x94, 0xa2, 0x56, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
|
||||
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
enum TextureType
|
||||
@@ -178,8 +178,8 @@ enum TextureType
|
||||
TEXTURE_EVENT,
|
||||
TEXTURE_TRIGGER,
|
||||
TEXTURE_PIVOT,
|
||||
TEXTURE_UNINTERPOLATED,
|
||||
TEXTURE_INTERPOLATED,
|
||||
TEXTURE_SQUARE,
|
||||
TEXTURE_CIRCLE,
|
||||
TEXTURE_PICKER,
|
||||
TEXTURE_FRAME_ALT,
|
||||
TEXTURE_FRAME,
|
||||
@@ -229,6 +229,8 @@ const vec2 ATLAS_UVS[TEXTURE_COUNT][2] =
|
||||
{ ATLAS_UV( 48, 64), ATLAS_UV( 88,104) } /* 40 x 40 */
|
||||
};
|
||||
|
||||
#define ATLAS_UV_ARGS(type) ATLAS_UVS[type][0], ATLAS_UVS[type][1]
|
||||
|
||||
const vec2 ATLAS_SIZES[TEXTURE_COUNT] =
|
||||
{
|
||||
TEXTURE_SIZE,
|
||||
@@ -277,7 +279,6 @@ enum ShaderType
|
||||
{
|
||||
SHADER_LINE,
|
||||
SHADER_TEXTURE,
|
||||
SHADER_LINE_DOTTED,
|
||||
SHADER_COUNT
|
||||
};
|
||||
|
||||
@@ -285,11 +286,8 @@ const std::string SHADER_VERTEX = R"(
|
||||
#version 330 core
|
||||
layout (location = 0) in vec2 i_position;
|
||||
layout (location = 1) in vec2 i_uv;
|
||||
|
||||
out vec2 i_uv_out;
|
||||
|
||||
uniform mat4 u_transform;
|
||||
|
||||
void main()
|
||||
{
|
||||
i_uv_out = i_uv;
|
||||
@@ -301,7 +299,6 @@ const std::string SHADER_FRAGMENT = R"(
|
||||
#version 330 core
|
||||
out vec4 o_fragColor;
|
||||
uniform vec4 u_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
o_fragColor = u_color;
|
||||
@@ -324,25 +321,6 @@ void main()
|
||||
}
|
||||
)";
|
||||
|
||||
const std::string SHADER_LINE_DOTTED_FRAGMENT = R"(
|
||||
#version 330 core
|
||||
uniform vec4 u_color;
|
||||
out vec4 o_fragColor;
|
||||
void main()
|
||||
{
|
||||
float patternX = mod(gl_FragCoord.x, 10.0);
|
||||
float patternY = mod(gl_FragCoord.y, 10.0);
|
||||
if (patternX < 5.0 || patternY < 5.0)
|
||||
{
|
||||
o_fragColor = u_color;
|
||||
}
|
||||
else
|
||||
{
|
||||
discard;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
#define SHADER_UNIFORM_COLOR "u_color"
|
||||
#define SHADER_UNIFORM_TRANSFORM "u_transform"
|
||||
#define SHADER_UNIFORM_TINT "u_tint"
|
||||
@@ -352,6 +330,5 @@ void main()
|
||||
const ShaderData SHADER_DATA[SHADER_COUNT] =
|
||||
{
|
||||
{SHADER_VERTEX, SHADER_FRAGMENT},
|
||||
{SHADER_VERTEX, SHADER_TEXTURE_FRAGMENT},
|
||||
{SHADER_VERTEX, SHADER_LINE_DOTTED_FRAGMENT}
|
||||
{SHADER_VERTEX, SHADER_TEXTURE_FRAGMENT}
|
||||
};
|
||||
|
367
src/anm2.cpp
367
src/anm2.cpp
@@ -11,7 +11,7 @@ static void _anm2_created_on_set(Anm2* self)
|
||||
std::tm localTime = *std::localtime(&time);
|
||||
|
||||
std::ostringstream timeString;
|
||||
timeString << std::put_time(&localTime, STRING_ANM2_CREATED_ON_FORMAT);
|
||||
timeString << std::put_time(&localTime, ANM2_CREATED_ON_FORMAT);
|
||||
self->createdOn = timeString.str();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// Spritesheets
|
||||
spritesheetsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_SPRITESHEETS]);
|
||||
|
||||
for (auto & [id, spritesheet] : self->spritesheets)
|
||||
for (auto& [id, spritesheet] : self->spritesheets)
|
||||
{
|
||||
XMLElement* spritesheetElement;
|
||||
|
||||
@@ -70,7 +70,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// Layers
|
||||
layersElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYERS]);
|
||||
|
||||
for (auto & [id, layer] : self->layers)
|
||||
for (auto& [id, layer] : self->layers)
|
||||
{
|
||||
XMLElement* layerElement;
|
||||
|
||||
@@ -88,7 +88,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// Nulls
|
||||
nullsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULLS]);
|
||||
|
||||
for (auto & [id, null] : self->nulls)
|
||||
for (auto& [id, null] : self->nulls)
|
||||
{
|
||||
XMLElement* nullElement;
|
||||
|
||||
@@ -108,7 +108,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// Events
|
||||
eventsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_EVENTS]);
|
||||
|
||||
for (auto & [id, event] : self->events)
|
||||
for (auto& [id, event] : self->events)
|
||||
{
|
||||
XMLElement* eventElement;
|
||||
|
||||
@@ -125,7 +125,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
|
||||
// Animations
|
||||
animationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATIONS]);
|
||||
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->defaultAnimation.c_str()); // DefaultAnimation
|
||||
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->animations[self->defaultAnimationID].name.c_str()); // DefaultAnimation
|
||||
|
||||
for (auto& [id, animation] : self->animations)
|
||||
{
|
||||
@@ -160,13 +160,13 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // YScale
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); // Delay
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], FLOAT_TO_U8(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], FLOAT_TO_U8(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], FLOAT_TO_U8(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], FLOAT_TO_U8(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], FLOAT_TO_U8(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], FLOAT_TO_U8(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], FLOAT_TO_U8(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated
|
||||
|
||||
@@ -189,7 +189,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_LAYER_ID], layerID); // LayerId
|
||||
layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], layerAnimation.isVisible); // Visible
|
||||
|
||||
for (auto & frame : layerAnimation.frames)
|
||||
for (auto& frame : layerAnimation.frames)
|
||||
{
|
||||
XMLElement* frameElement;
|
||||
|
||||
@@ -208,13 +208,13 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // YScale
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); /* Delay */
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], FLOAT_TO_U8(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], FLOAT_TO_U8(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], FLOAT_TO_U8(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], FLOAT_TO_U8(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], FLOAT_TO_U8(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], FLOAT_TO_U8(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], FLOAT_TO_U8(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated
|
||||
|
||||
@@ -229,7 +229,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// NullAnimations
|
||||
nullAnimationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULL_ANIMATIONS]);
|
||||
|
||||
for (const auto & [nullID, nullAnimation] : animation.nullAnimations)
|
||||
for (const auto& [nullID, nullAnimation] : animation.nullAnimations)
|
||||
{
|
||||
XMLElement* nullAnimationElement;
|
||||
|
||||
@@ -238,7 +238,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NULL_ID], nullID); // NullId
|
||||
nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], nullAnimation.isVisible); // Visible
|
||||
|
||||
for (const auto & frame : nullAnimation.frames)
|
||||
for (const auto& frame : nullAnimation.frames)
|
||||
{
|
||||
XMLElement* frameElement;
|
||||
|
||||
@@ -253,13 +253,13 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // XScale
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); // Delay
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], FLOAT_TO_U8(frame.tintRGBA.r)); // RedTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], FLOAT_TO_U8(frame.tintRGBA.g)); // GreenTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], FLOAT_TO_U8(frame.tintRGBA.b)); // BlueTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], FLOAT_TO_U8(frame.tintRGBA.a)); // AlphaTint
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], FLOAT_TO_U8(frame.offsetRGB.r)); // RedOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], FLOAT_TO_U8(frame.offsetRGB.g)); // GreenOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], FLOAT_TO_U8(frame.offsetRGB.b)); // BlueOffset
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation
|
||||
frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated
|
||||
|
||||
@@ -274,7 +274,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
||||
// Triggers
|
||||
triggersElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGERS]);
|
||||
|
||||
for (const auto & frame : animation.triggers.frames)
|
||||
for (const auto& frame : animation.triggers.frames)
|
||||
{
|
||||
XMLElement* triggerElement;
|
||||
|
||||
@@ -328,10 +328,11 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
s32 layerMapIndex = 0;
|
||||
bool isLayerMapSet = false;
|
||||
bool isFirstAnimationDone = false;
|
||||
std::string defaultAnimation{};
|
||||
|
||||
if (!self || path.empty()) return false;
|
||||
|
||||
*self = Anm2{};
|
||||
anm2_new(self);
|
||||
|
||||
xmlError = xmlDocument.LoadFile(path.c_str());
|
||||
|
||||
@@ -418,13 +419,13 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
self->createdOn = xmlAttribute->Value();
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_VERSION: // Version
|
||||
self->version = atoi(xmlAttribute->Value());
|
||||
self->version = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_FPS: // FPS
|
||||
self->fps = atoi(xmlAttribute->Value());
|
||||
self->fps = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ID: // ID
|
||||
id = atoi(xmlAttribute->Value());
|
||||
id = std::atoi(xmlAttribute->Value());
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_SPRITESHEET: // Spritesheet
|
||||
@@ -448,7 +449,7 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_LAYER_ID: // LayerId
|
||||
id = atoi(xmlAttribute->Value());
|
||||
id = std::atoi(xmlAttribute->Value());
|
||||
|
||||
if (!isLayerMapSet)
|
||||
{
|
||||
@@ -460,7 +461,7 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
item = &animation->layerAnimations[id];
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_NULL_ID: // NullId
|
||||
id = atoi(xmlAttribute->Value());
|
||||
id = std::atoi(xmlAttribute->Value());
|
||||
animation->nullAnimations[id] = addItem;
|
||||
item = &animation->nullAnimations[id];
|
||||
break;
|
||||
@@ -487,52 +488,52 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_SPRITESHEET_ID:
|
||||
layer->spritesheetID = atoi(xmlAttribute->Value());
|
||||
layer->spritesheetID = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_SHOW_RECT:
|
||||
null->isShowRect = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_DEFAULT_ANIMATION:
|
||||
self->defaultAnimation = xmlAttribute->Value();
|
||||
defaultAnimation = xmlAttribute->Value();
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_FRAME_NUM:
|
||||
animation->frameNum = atoi(xmlAttribute->Value());
|
||||
animation->frameNum = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_LOOP:
|
||||
animation->isLoop = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_POSITION:
|
||||
frame->position.x = atof(xmlAttribute->Value());
|
||||
frame->position.x = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_POSITION:
|
||||
frame->position.y = atof(xmlAttribute->Value());
|
||||
frame->position.y = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_PIVOT:
|
||||
frame->pivot.x = atof(xmlAttribute->Value());
|
||||
frame->pivot.x = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_PIVOT:
|
||||
frame->pivot.y = atof(xmlAttribute->Value());
|
||||
frame->pivot.y = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_CROP:
|
||||
frame->crop.x = atof(xmlAttribute->Value());
|
||||
frame->crop.x = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_CROP:
|
||||
frame->crop.y = atof(xmlAttribute->Value());
|
||||
frame->crop.y = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_WIDTH:
|
||||
frame->size.x = atof(xmlAttribute->Value());
|
||||
frame->size.x = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_HEIGHT:
|
||||
frame->size.y = atof(xmlAttribute->Value());
|
||||
frame->size.y = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_SCALE:
|
||||
frame->scale.x = atof(xmlAttribute->Value());
|
||||
frame->scale.x = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_SCALE:
|
||||
frame->scale.y = atof(xmlAttribute->Value());
|
||||
frame->scale.y = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_DELAY:
|
||||
frame->delay = atoi(xmlAttribute->Value());
|
||||
frame->delay = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_VISIBLE:
|
||||
switch (anm2Element)
|
||||
@@ -550,37 +551,37 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_RED_TINT:
|
||||
frame->tintRGBA.r = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->tintRGBA.r = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_GREEN_TINT:
|
||||
frame->tintRGBA.g = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->tintRGBA.g = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_BLUE_TINT:
|
||||
frame->tintRGBA.b = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->tintRGBA.b = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ALPHA_TINT:
|
||||
frame->tintRGBA.a = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->tintRGBA.a = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_RED_OFFSET:
|
||||
frame->offsetRGB.r = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->offsetRGB.r = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_GREEN_OFFSET:
|
||||
frame->offsetRGB.g = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->offsetRGB.g = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_BLUE_OFFSET:
|
||||
frame->offsetRGB.b = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
frame->offsetRGB.b = U8_TO_FLOAT(std::atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ROTATION:
|
||||
frame->rotation = atof(xmlAttribute->Value());
|
||||
frame->rotation = std::atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_INTERPOLATED:
|
||||
frame->isInterpolated = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_EVENT_ID:
|
||||
frame->eventID = atoi(xmlAttribute->Value());
|
||||
frame->eventID = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_AT_FRAME:
|
||||
frame->atFrame = atoi(xmlAttribute->Value());
|
||||
frame->atFrame = std::atoi(xmlAttribute->Value());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -589,7 +590,8 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
xmlAttribute = xmlAttribute->Next();
|
||||
}
|
||||
|
||||
if (anm2Element == ANM2_ELEMENT_SPRITESHEET) resources_texture_init(resources, spritesheet->path , id);
|
||||
if (anm2Element == ANM2_ELEMENT_SPRITESHEET)
|
||||
resources_texture_init(resources, spritesheet->path , id);
|
||||
|
||||
xmlChild = xmlElement->FirstChildElement();
|
||||
|
||||
@@ -615,6 +617,11 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
}
|
||||
}
|
||||
|
||||
// Set default animation ID
|
||||
for (auto& [id, animation] : self->animations)
|
||||
if (animation.name == defaultAnimation)
|
||||
self->defaultAnimationID = id;
|
||||
|
||||
log_info(std::format(ANM2_READ_INFO, path));
|
||||
|
||||
// Return to old working directory
|
||||
@@ -625,24 +632,48 @@ bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path)
|
||||
|
||||
void anm2_layer_add(Anm2* self)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
s32 id = map_next_id_get(self->layers);
|
||||
|
||||
self->layers[id] = Anm2Layer{};
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
self->layerMap[self->layers.size() - 1] = id;
|
||||
|
||||
for (auto& [_, animation] : self->animations)
|
||||
animation.layerAnimations[id] = Anm2Item{};
|
||||
}
|
||||
|
||||
void anm2_layer_remove(Anm2* self, s32 id)
|
||||
{
|
||||
// Make sure the layer exists
|
||||
auto it = self->layers.find(id);
|
||||
if (it == self->layers.end())
|
||||
return;
|
||||
if (!self->layers.contains(id))
|
||||
return;
|
||||
|
||||
self->layers.erase(id);
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
for (auto it = self->layerMap.begin(); it != self->layerMap.end(); ++it)
|
||||
{
|
||||
if (it->second == id)
|
||||
{
|
||||
self->layerMap.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<s32, s32> newLayerMap;
|
||||
s32 newIndex = 0;
|
||||
|
||||
for (const auto& [_, layerID] : self->layerMap)
|
||||
newLayerMap[newIndex++] = layerID;
|
||||
|
||||
self->layerMap = std::move(newLayerMap);
|
||||
|
||||
for (auto& [_, animation] : self->animations)
|
||||
animation.layerAnimations.erase(id);
|
||||
}
|
||||
|
||||
@@ -652,23 +683,40 @@ void anm2_null_add(Anm2* self)
|
||||
|
||||
self->nulls[id] = Anm2Null{};
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
for (auto& [_, animation] : self->animations)
|
||||
animation.nullAnimations[id] = Anm2Item{};
|
||||
}
|
||||
|
||||
void anm2_null_remove(Anm2* self, s32 id)
|
||||
{
|
||||
// Make sure the null exists
|
||||
auto it = self->nulls.find(id);
|
||||
if (it == self->nulls.end())
|
||||
return;
|
||||
if (!self->nulls.contains(id))
|
||||
return;
|
||||
|
||||
self->nulls.erase(id);
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
animation.nullAnimations.erase(id);
|
||||
std::map<s32, Anm2Null> newNulls;
|
||||
s32 newID = 0;
|
||||
|
||||
for (const auto& [_, null] : self->nulls)
|
||||
newNulls[newID++] = null;
|
||||
|
||||
self->nulls = std::move(newNulls);
|
||||
|
||||
for (auto& [_, animation] : self->animations)
|
||||
{
|
||||
if (animation.nullAnimations.contains(id))
|
||||
animation.nullAnimations.erase(id);
|
||||
|
||||
std::map<s32, Anm2Item> newNullAnims;
|
||||
s32 newAnimID = 0;
|
||||
for (const auto& [_, nullAnim] : animation.nullAnimations)
|
||||
newNullAnims[newAnimID++] = nullAnim;
|
||||
|
||||
animation.nullAnimations = std::move(newNullAnims);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
s32 anm2_animation_add(Anm2* self)
|
||||
{
|
||||
s32 id = map_next_id_get(self->animations);
|
||||
@@ -676,7 +724,7 @@ s32 anm2_animation_add(Anm2* self)
|
||||
|
||||
for (auto& [layerID, layer] : self->layers)
|
||||
animation.layerAnimations[layerID] = Anm2Item{};
|
||||
for (auto & [nullID, null] : self->nulls)
|
||||
for (auto& [nullID, null] : self->nulls)
|
||||
animation.nullAnimations[nullID] = Anm2Item{};
|
||||
|
||||
animation.rootAnimation.frames.push_back(Anm2Frame{});
|
||||
@@ -699,13 +747,19 @@ void anm2_new(Anm2* self)
|
||||
|
||||
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference* reference)
|
||||
{
|
||||
auto it = self->animations.find(reference->animationID);
|
||||
if (it == self->animations.end()) return nullptr;
|
||||
return &it->second;
|
||||
if (reference->animationID == ID_NONE) return nullptr;
|
||||
|
||||
if (!self->animations.contains(reference->animationID))
|
||||
return nullptr;
|
||||
|
||||
return &self->animations[reference->animationID];
|
||||
}
|
||||
|
||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference)
|
||||
{
|
||||
if (reference->itemType == ANM2_NONE)
|
||||
return nullptr;
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_reference(self, reference);
|
||||
|
||||
if (!animation) return nullptr;
|
||||
@@ -715,19 +769,11 @@ Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference)
|
||||
case ANM2_ROOT:
|
||||
return &animation->rootAnimation;
|
||||
case ANM2_LAYER:
|
||||
{
|
||||
auto it = animation->layerAnimations.find(reference->itemID);
|
||||
if (it == animation->layerAnimations.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
if (!animation->layerAnimations.contains(reference->itemID)) return nullptr;
|
||||
return &animation->layerAnimations[reference->itemID];
|
||||
case ANM2_NULL:
|
||||
{
|
||||
auto it = animation->nullAnimations.find(reference->itemID);
|
||||
if (it == animation->nullAnimations.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
if (!animation->nullAnimations.contains(reference->itemID)) return nullptr;
|
||||
return &animation->nullAnimations[reference->itemID];
|
||||
case ANM2_TRIGGERS:
|
||||
return &animation->triggers;
|
||||
default:
|
||||
@@ -740,7 +786,9 @@ Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference)
|
||||
Anm2Item* item = anm2_item_from_reference(self, reference);
|
||||
|
||||
if (!item) return nullptr;
|
||||
if (reference->frameIndex < 0 || reference->frameIndex >= (s32)item->frames.size()) return nullptr;
|
||||
|
||||
if (reference->frameIndex <= INDEX_NONE || reference->frameIndex >= (s32)item->frames.size())
|
||||
return nullptr;
|
||||
|
||||
return &item->frames[reference->frameIndex];
|
||||
}
|
||||
@@ -777,19 +825,19 @@ void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference,
|
||||
Anm2Animation* animation = anm2_animation_from_reference(self, &reference);
|
||||
|
||||
if (!animation) return;
|
||||
if (time < 0 || time > animation->frameNum) return;
|
||||
|
||||
time = std::clamp(time, 0.0f, animation->frameNum - 1.0f);
|
||||
|
||||
Anm2Item* item = anm2_item_from_reference(self, &reference);
|
||||
|
||||
if (!item) return;
|
||||
|
||||
Anm2Frame* nextFrame = nullptr;
|
||||
Anm2Frame* frameNext = nullptr;
|
||||
s32 delayCurrent = 0;
|
||||
s32 delayNext = 0;
|
||||
|
||||
for (auto [i, iFrame] : std::views::enumerate(item->frames))
|
||||
{
|
||||
|
||||
if (reference.itemType == ANM2_TRIGGERS)
|
||||
{
|
||||
if ((s32)time == iFrame.atFrame)
|
||||
@@ -807,9 +855,9 @@ void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference,
|
||||
if (time >= delayCurrent && time < delayNext)
|
||||
{
|
||||
if (i + 1 < (s32)item->frames.size())
|
||||
nextFrame = &item->frames[i + 1];
|
||||
frameNext = &item->frames[i + 1];
|
||||
else
|
||||
nextFrame = nullptr;
|
||||
frameNext = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -820,15 +868,15 @@ void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference,
|
||||
if (reference.itemType == ANM2_TRIGGERS)
|
||||
return;
|
||||
|
||||
if (frame->isInterpolated && nextFrame)
|
||||
if (frame->isInterpolated && frameNext && frame->delay > 1)
|
||||
{
|
||||
f32 interpolationTime = (time - delayCurrent) / (delayNext - delayCurrent);
|
||||
f32 interpolation = (time - delayCurrent) / (delayNext - delayCurrent);
|
||||
|
||||
frame->rotation = glm::mix(frame->rotation, nextFrame->rotation, interpolationTime);;
|
||||
frame->position = glm::mix(frame->position, nextFrame->position, interpolationTime);;
|
||||
frame->scale = glm::mix(frame->scale, nextFrame->scale, interpolationTime);;
|
||||
frame->offsetRGB = glm::mix(frame->offsetRGB, nextFrame->offsetRGB, interpolationTime);;
|
||||
frame->tintRGBA = glm::mix(frame->tintRGBA, nextFrame->tintRGBA, interpolationTime);;
|
||||
frame->rotation = glm::mix(frame->rotation, frameNext->rotation, interpolation);
|
||||
frame->position = glm::mix(frame->position, frameNext->position, interpolation);
|
||||
frame->scale = glm::mix(frame->scale, frameNext->scale, interpolation);
|
||||
frame->offsetRGB = glm::mix(frame->offsetRGB, frameNext->offsetRGB, interpolation);
|
||||
frame->tintRGBA = glm::mix(frame->tintRGBA, frameNext->tintRGBA, interpolation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,7 +918,8 @@ Anm2Frame* anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time)
|
||||
Anm2Animation* animation = anm2_animation_from_reference(self, reference);
|
||||
Anm2Item* item = anm2_item_from_reference(self, reference);
|
||||
|
||||
if (!animation || !item) return nullptr;
|
||||
if (!animation || !item)
|
||||
return nullptr;
|
||||
|
||||
if (item)
|
||||
{
|
||||
@@ -879,7 +928,7 @@ Anm2Frame* anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time)
|
||||
|
||||
if (reference->itemType == ANM2_TRIGGERS)
|
||||
{
|
||||
for (auto & frameCheck : item->frames) if (frameCheck.atFrame == time) return nullptr;
|
||||
for (auto& frameCheck : item->frames) if (frameCheck.atFrame == time) return nullptr;
|
||||
|
||||
frame.atFrame = time;
|
||||
index = item->frames.size();
|
||||
@@ -888,7 +937,7 @@ Anm2Frame* anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time)
|
||||
{
|
||||
s32 frameDelayCount = 0;
|
||||
|
||||
for (auto & frameCheck : item->frames)
|
||||
for (auto& frameCheck : item->frames)
|
||||
frameDelayCount += frameCheck.delay;
|
||||
|
||||
if (frameDelayCount + ANM2_FRAME_DELAY_MIN > animation->frameNum) return nullptr;
|
||||
@@ -929,4 +978,106 @@ void anm2_reference_item_clear(Anm2Reference* self)
|
||||
void anm2_reference_frame_clear(Anm2Reference* self)
|
||||
{
|
||||
self->frameIndex = INDEX_NONE;
|
||||
}
|
||||
|
||||
void anm2_animation_merge(Anm2* self, s32 animationID, const std::vector<s32>& mergeIDs, Anm2MergeType type)
|
||||
{
|
||||
Anm2Animation newAnimation = self->animations[animationID];
|
||||
|
||||
newAnimation.rootAnimation.frames.clear();
|
||||
|
||||
for (auto& [id, layerAnimation] : newAnimation.layerAnimations)
|
||||
layerAnimation.frames.clear();
|
||||
|
||||
for (auto& [id, nullAnimation] : newAnimation.nullAnimations)
|
||||
nullAnimation.frames.clear();
|
||||
|
||||
newAnimation.triggers.frames.clear();
|
||||
|
||||
auto merge_item = [&](Anm2Item& destinationItem, const Anm2Item& sourceItem)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ANM2_MERGE_APPEND_FRAMES:
|
||||
destinationItem.frames.insert(destinationItem.frames.end(), sourceItem.frames.begin(), sourceItem.frames.end());
|
||||
break;
|
||||
case ANM2_MERGE_PREPEND_FRAMES:
|
||||
destinationItem.frames.insert(destinationItem.frames.begin(), sourceItem.frames.begin(), sourceItem.frames.end());
|
||||
break;
|
||||
case ANM2_MERGE_REPLACE_FRAMES:
|
||||
if (destinationItem.frames.size() < sourceItem.frames.size())
|
||||
destinationItem.frames.resize(sourceItem.frames.size());
|
||||
for (s32 i = 0; i < (s32)sourceItem.frames.size(); i++)
|
||||
destinationItem.frames[i] = sourceItem.frames[i];
|
||||
break;
|
||||
case ANM2_MERGE_IGNORE:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto mergeID : mergeIDs)
|
||||
{
|
||||
const Anm2Animation& mergeAnimation = self->animations[mergeID];
|
||||
|
||||
merge_item(newAnimation.rootAnimation, mergeAnimation.rootAnimation);
|
||||
|
||||
for (const auto& [id, layerAnimation] : mergeAnimation.layerAnimations)
|
||||
merge_item(newAnimation.layerAnimations[id], layerAnimation);
|
||||
|
||||
for (const auto& [id, nullAnimation] : mergeAnimation.nullAnimations)
|
||||
merge_item(newAnimation.nullAnimations[id], nullAnimation);
|
||||
|
||||
merge_item(newAnimation.triggers, mergeAnimation.triggers);
|
||||
}
|
||||
|
||||
self->animations[animationID] = newAnimation;
|
||||
|
||||
anm2_animation_length_set(&self->animations[animationID]);
|
||||
}
|
||||
|
||||
void anm2_frame_bake(Anm2* self, Anm2Reference* reference, s32 interval, bool isRoundScale, bool isRoundRotation)
|
||||
{
|
||||
Anm2Item* item = anm2_item_from_reference(self, reference);
|
||||
if (!item) return;
|
||||
|
||||
Anm2Frame* frame = anm2_frame_from_reference(self, reference);
|
||||
if (!frame) return;
|
||||
|
||||
Anm2Reference referenceNext = *reference;
|
||||
referenceNext.frameIndex = reference->frameIndex + 1;
|
||||
|
||||
Anm2Frame* frameNext = anm2_frame_from_reference(self, &referenceNext);
|
||||
if (!frameNext) return;
|
||||
|
||||
const Anm2Frame baseFrame = *frame;
|
||||
const Anm2Frame baseFrameNext = *frameNext;
|
||||
|
||||
s32 delay = 0;
|
||||
s32 insertIndex = reference->frameIndex;
|
||||
|
||||
while (delay < baseFrame.delay)
|
||||
{
|
||||
f32 interpolation = (f32)delay / baseFrame.delay;
|
||||
|
||||
Anm2Frame baked = *frame;
|
||||
baked.delay = std::min(interval, baseFrame.delay - delay);
|
||||
baked.isInterpolated = (insertIndex == reference->frameIndex) ? baseFrame.isInterpolated : false;
|
||||
|
||||
baked.rotation = glm::mix(baseFrame.rotation, baseFrameNext.rotation, interpolation);
|
||||
baked.position = glm::mix(baseFrame.position, baseFrameNext.position, interpolation);
|
||||
baked.scale = glm::mix(baseFrame.scale, baseFrameNext.scale, interpolation);
|
||||
baked.offsetRGB = glm::mix(baseFrame.offsetRGB, baseFrameNext.offsetRGB, interpolation);
|
||||
baked.tintRGBA = glm::mix(baseFrame.tintRGBA, baseFrameNext.tintRGBA, interpolation);
|
||||
|
||||
if (isRoundScale) baked.scale = vec2((s32)baked.scale.x, (s32)baked.scale.y);
|
||||
if (isRoundRotation) baked.rotation = (s32)baked.rotation;
|
||||
|
||||
if (insertIndex == reference->frameIndex)
|
||||
item->frames[insertIndex] = baked;
|
||||
else
|
||||
item->frames.insert(item->frames.begin() + insertIndex, baked);
|
||||
insertIndex++;
|
||||
|
||||
delay += baked.delay;
|
||||
}
|
||||
}
|
34
src/anm2.h
34
src/anm2.h
@@ -17,7 +17,7 @@
|
||||
#define ANM2_READ_INFO "Read anm2 from file: {}"
|
||||
#define ANM2_WRITE_ERROR "Failed to write anm2 to file: {}"
|
||||
#define ANM2_WRITE_INFO "Wrote anm2 to file: {}"
|
||||
#define STRING_ANM2_CREATED_ON_FORMAT "%d-%B-%Y %I:%M:%S %p"
|
||||
#define ANM2_CREATED_ON_FORMAT "%d-%B-%Y %I:%M:%S %p"
|
||||
|
||||
/* Elements */
|
||||
#define ANM2_ELEMENT_LIST \
|
||||
@@ -132,7 +132,7 @@ struct Anm2Spritesheet
|
||||
struct Anm2Layer
|
||||
{
|
||||
std::string name = "New Layer";
|
||||
s32 spritesheetID = -1;
|
||||
s32 spritesheetID = ID_NONE;
|
||||
};
|
||||
|
||||
struct Anm2Null
|
||||
@@ -154,12 +154,12 @@ struct Anm2Frame
|
||||
s32 delay = ANM2_FRAME_DELAY_MIN;
|
||||
s32 atFrame = INDEX_NONE;
|
||||
s32 eventID = ID_NONE;
|
||||
vec2 crop = {0.0f, 0.0f};
|
||||
vec2 pivot = {0.0f, 0.0f};
|
||||
vec2 position = {0.0f, 0.0f};
|
||||
vec2 size = {0.0f, 0.0f};
|
||||
vec2 scale = {100.0f, 100.0f};
|
||||
vec3 offsetRGB = {0.0f, 0.0f, 0.0f};
|
||||
vec2 crop{};
|
||||
vec2 pivot{};
|
||||
vec2 position{};
|
||||
vec2 size{};
|
||||
vec2 scale{};
|
||||
vec3 offsetRGB{};
|
||||
vec4 tintRGBA = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
|
||||
@@ -183,7 +183,6 @@ struct Anm2Animation
|
||||
struct Anm2
|
||||
{
|
||||
std::string path{};
|
||||
std::string defaultAnimation{};
|
||||
std::string createdBy = "robot";
|
||||
std::string createdOn{};
|
||||
std::map<s32, Anm2Spritesheet> spritesheets;
|
||||
@@ -191,9 +190,10 @@ struct Anm2
|
||||
std::map<s32, Anm2Null> nulls;
|
||||
std::map<s32, Anm2Event> events;
|
||||
std::map<s32, Anm2Animation> animations;
|
||||
std::map<s32, s32> layerMap; // id, index
|
||||
std::map<s32, s32> layerMap; // index, id
|
||||
s32 defaultAnimationID{};
|
||||
s32 fps = 30;
|
||||
s32 version = 0;
|
||||
s32 version{};
|
||||
};
|
||||
|
||||
struct Anm2Reference
|
||||
@@ -223,6 +223,14 @@ struct Anm2FrameWithReference
|
||||
Anm2Frame frame;
|
||||
};
|
||||
|
||||
enum Anm2MergeType
|
||||
{
|
||||
ANM2_MERGE_APPEND_FRAMES,
|
||||
ANM2_MERGE_REPLACE_FRAMES,
|
||||
ANM2_MERGE_PREPEND_FRAMES,
|
||||
ANM2_MERGE_IGNORE
|
||||
};
|
||||
|
||||
void anm2_layer_add(Anm2* self);
|
||||
void anm2_layer_remove(Anm2* self, s32 id);
|
||||
void anm2_null_add(Anm2* self);
|
||||
@@ -244,4 +252,6 @@ void anm2_reference_clear(Anm2Reference* self);
|
||||
void anm2_reference_item_clear(Anm2Reference* self);
|
||||
void anm2_reference_frame_clear(Anm2Reference* self);
|
||||
s32 anm2_animation_length_get(Anm2Animation* self);
|
||||
void anm2_animation_length_set(Anm2Animation* self);
|
||||
void anm2_animation_length_set(Anm2Animation* self);
|
||||
void anm2_animation_merge(Anm2* self, s32 animationID, const std::vector<s32>& mergeIDs, Anm2MergeType type);
|
||||
void anm2_frame_bake(Anm2* self, Anm2Reference* reference, s32 interval, bool isRoundScale, bool isRoundRotation);
|
283
src/canvas.cpp
283
src/canvas.cpp
@@ -2,10 +2,19 @@
|
||||
|
||||
#include "canvas.h"
|
||||
|
||||
void canvas_init(Canvas* self, vec2 size)
|
||||
static void _canvas_texture_free(Canvas* self)
|
||||
{
|
||||
self->size = size;
|
||||
if (self->fbo != 0) glDeleteFramebuffers(1, &self->fbo);
|
||||
if (self->rbo != 0) glDeleteRenderbuffers(1, &self->rbo);
|
||||
if (self->texture != 0) glDeleteTextures(1, &self->texture);
|
||||
}
|
||||
|
||||
static void _canvas_texture_init(Canvas* self, vec2& size)
|
||||
{
|
||||
_canvas_texture_free(self);
|
||||
|
||||
self->size = size;
|
||||
|
||||
glGenFramebuffers(1, &self->fbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
@@ -24,6 +33,43 @@ void canvas_init(Canvas* self, vec2 size)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void canvas_init(Canvas* self)
|
||||
{
|
||||
// Axis
|
||||
glGenVertexArrays(1, &self->axisVAO);
|
||||
glGenBuffers(1, &self->axisVBO);
|
||||
|
||||
glBindVertexArray(self->axisVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->axisVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(CANVAS_AXIS_VERTICES), CANVAS_AXIS_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
// Grid
|
||||
glGenVertexArrays(1, &self->gridVAO);
|
||||
glGenBuffers(1, &self->gridVBO);
|
||||
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->gridVBO);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
// Rect
|
||||
glGenVertexArrays(1, &self->rectVAO);
|
||||
glGenBuffers(1, &self->rectVBO);
|
||||
|
||||
glBindVertexArray(self->rectVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_VERTICES), GL_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
// Texture
|
||||
glGenVertexArrays(1, &self->textureVAO);
|
||||
@@ -36,15 +82,240 @@ void canvas_init(Canvas* self, vec2 size)
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(f32) * 4 * 4, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_DYNAMIC_DRAW);
|
||||
|
||||
// Position attribute
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0);
|
||||
|
||||
// UV attribute
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32)));
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
mat4 canvas_transform_get(Canvas* self, vec2& pan, f32& zoom, OriginType origin)
|
||||
{
|
||||
f32 zoomFactor = PERCENT_TO_UNIT(zoom);
|
||||
mat4 projection = glm::ortho(0.0f, self->size.x, 0.0f, self->size.y, -1.0f, 1.0f);
|
||||
mat4 view = mat4{1.0f};
|
||||
|
||||
switch (origin)
|
||||
{
|
||||
case ORIGIN_TOP_LEFT:
|
||||
view = glm::translate(view, vec3(pan, 0.0f));
|
||||
break;
|
||||
default:
|
||||
view = glm::translate(view, vec3((self->size * 0.5f) + pan, 0.0f));
|
||||
break;
|
||||
}
|
||||
|
||||
view = glm::scale(view, vec3(zoomFactor, zoomFactor, 1.0f));
|
||||
|
||||
return projection * view;
|
||||
}
|
||||
|
||||
void canvas_clear(vec4& color)
|
||||
{
|
||||
glClearColor(color.r, color.g, color.b, color.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void canvas_viewport_set(Canvas* self)
|
||||
{
|
||||
glViewport(0, 0, (s32)self->size.x, (s32)self->size.y);
|
||||
}
|
||||
|
||||
void canvas_texture_set(Canvas* self)
|
||||
{
|
||||
static vec2 previousSize = {-1, -1};
|
||||
|
||||
if (previousSize != self->size)
|
||||
{
|
||||
_canvas_texture_init(self, self->size);
|
||||
previousSize = self->size;
|
||||
}
|
||||
}
|
||||
|
||||
void canvas_grid_draw(Canvas* self, GLuint& shader, mat4& transform, f32& zoom, ivec2& size, ivec2& offset, vec4& color)
|
||||
{
|
||||
if (size.x <= 0 || size.y <= 0)
|
||||
return; // avoid div-by-zero
|
||||
|
||||
std::vector<f32> vertices;
|
||||
|
||||
vec2 gridSize = self->size * (PERCENT_TO_UNIT(CANVAS_ZOOM_MAX - zoom));
|
||||
|
||||
// First visible vertical line <= 0
|
||||
s32 startX = -(offset.x % size.x);
|
||||
if (startX > 0) startX -= size.x;
|
||||
|
||||
for (s32 x = startX; x <= gridSize.x; x += size.x)
|
||||
{
|
||||
vertices.push_back((f32)x);
|
||||
vertices.push_back(0.0f);
|
||||
vertices.push_back((f32)x);
|
||||
vertices.push_back((f32)gridSize.y);
|
||||
}
|
||||
|
||||
// First visible horizontal line <= 0
|
||||
s32 startY = -(offset.y % size.y);
|
||||
if (startY > 0) startY -= size.y;
|
||||
|
||||
for (s32 y = startY; y <= gridSize.y; y += size.y)
|
||||
{
|
||||
vertices.push_back(0.0f);
|
||||
vertices.push_back((f32)y);
|
||||
vertices.push_back((f32)gridSize.x);
|
||||
vertices.push_back((f32)y);
|
||||
}
|
||||
|
||||
s32 vertexCount = (s32)vertices.size() / 2;
|
||||
|
||||
if (vertexCount == 0)
|
||||
return;
|
||||
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->gridVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(f32), vertices.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
glUseProgram(shader);
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform));
|
||||
glUniform4f(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR), color.r, color.g, color.b, color.a);
|
||||
glDrawArrays(GL_LINES, 0, vertexCount);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void canvas_texture_draw(Canvas* self, GLuint& shader, GLuint& texture, mat4& transform, const f32* vertices, vec4 tint, vec3 colorOffset)
|
||||
{
|
||||
glUseProgram(shader);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_UV_VERTICES), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shader, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform3fv(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(colorOffset));
|
||||
glUniform4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TINT), 1, value_ptr(tint));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform, const vec4& color)
|
||||
{
|
||||
glUseProgram(shader);
|
||||
|
||||
glBindVertexArray(self->rectVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform));
|
||||
glUniform4fv(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR), 1, value_ptr(color));
|
||||
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void canvas_rect_dotted_draw(Canvas* self, const GLuint& shader, const mat4& transform, const vec4& color)
|
||||
{
|
||||
glUseProgram(shader);
|
||||
|
||||
glBindVertexArray(self->rectVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform));
|
||||
glUniform4fv(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR), 1, value_ptr(color));
|
||||
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color)
|
||||
{
|
||||
glUseProgram(shader);
|
||||
glBindVertexArray(self->axisVAO);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(transform));
|
||||
glUniform4f(glGetUniformLocation(shader, SHADER_UNIFORM_COLOR), color.r, color.g, color.b, color.a);
|
||||
glDrawArrays(GL_LINES, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void canvas_bind(Canvas* self)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
}
|
||||
|
||||
void canvas_unbind(void)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void canvas_free(Canvas* self)
|
||||
{
|
||||
_canvas_texture_free(self);
|
||||
}
|
||||
|
||||
mat4 canvas_mvp_get(mat4& transform, vec2 size, vec2 position, vec2 pivot, f32 rotation, vec2 scale, vec2 pivotAlt, f32 rotationAlt)
|
||||
{
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
f32 usedSign = (scaleSign.x * scaleSign.y) < 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
vec2 sizeScaled = size * scaleAbsolute;
|
||||
vec2 pivotScaled = pivot * scaleAbsolute;
|
||||
vec2 pivotAltScaled = pivotAlt * scaleAbsolute;
|
||||
|
||||
vec2 pivotAltMirrored = pivotScaled + (pivotAltScaled - pivotScaled) * scaleSign;
|
||||
|
||||
mat4 model = glm::translate(mat4(1.0f), vec3(position - pivotScaled, 0.0f));
|
||||
model = glm::translate(model, vec3(pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(scaleSign, 1.0f));
|
||||
model = glm::rotate(model, glm::radians(rotation) * usedSign, vec3(0,0,1));
|
||||
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
|
||||
model = glm::translate(model, vec3(pivotAltMirrored, 0.0f));
|
||||
model = glm::rotate(model, glm::radians(rotationAlt) * usedSign, vec3(0,0,1));
|
||||
model = glm::translate(model, vec3(-pivotAltMirrored, 0.0f));
|
||||
model = glm::scale(model, vec3(sizeScaled, 1.0f));
|
||||
|
||||
return transform * model;
|
||||
}
|
||||
|
||||
/*
|
||||
mat4 canvas_mvp_get(mat4& transform, vec2 size, vec2 position, vec2 pivot, f32 rotation, vec2 scale, vec2 pivotAlt, f32 rotationAlt)
|
||||
{
|
||||
vec2 scaleAbsolute = abs(scale);
|
||||
vec2 signScale = glm::sign(scale);
|
||||
vec2 pivotScaled = pivot * scaleAbsolute;
|
||||
vec2 pivotAltScaled = pivotAlt * scaleAbsolute;
|
||||
vec2 sizeScaled = size * scaleAbsolute;
|
||||
|
||||
mat4 model = glm::translate(mat4(1.0f), vec3(position - pivotScaled, 0.0f));
|
||||
|
||||
model = glm::translate(model, vec3(pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(signScale, 1.0f)); // Flip
|
||||
model = glm::rotate(model, radians(rotation), vec3(0,0,1));
|
||||
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
|
||||
|
||||
model = glm::translate(model, vec3(pivotAltScaled, 0.0f));
|
||||
model = glm::rotate(model, radians(rotationAlt), vec3(0,0,1));
|
||||
model = glm::translate(model, vec3(-pivotAltScaled, 0.0f));
|
||||
|
||||
model = glm::scale(model, vec3(sizeScaled, 1.0f));
|
||||
|
||||
return transform * model;
|
||||
}
|
||||
*/
|
82
src/canvas.h
82
src/canvas.h
@@ -1,33 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "texture.h"
|
||||
#include "shader.h"
|
||||
#include "resources.h"
|
||||
|
||||
#define CANVAS_ZOOM_MIN 1
|
||||
#define CANVAS_ZOOM_MAX 1000
|
||||
#define CANVAS_ZOOM_STEP 25
|
||||
#define CANVAS_LINE_LENGTH 100000.0f
|
||||
#define CANVAS_GRID_RANGE 100
|
||||
#define CANVAS_ZOOM_MIN 1.0f
|
||||
#define CANVAS_ZOOM_MAX 2000.0f
|
||||
#define CANVAS_ZOOM_STEP 10.0f
|
||||
#define CANVAS_ZOOM_MOD 10.0f
|
||||
#define CANVAS_GRID_MIN 1
|
||||
#define CANVAS_GRID_MAX 100
|
||||
#define CANVAS_GRID_MAX 1000
|
||||
#define CANVAS_LINE_LENGTH (FLT_MAX * 0.001f)
|
||||
|
||||
static const vec2 CANVAS_GRID_SIZE = {3200, 1600};
|
||||
static const vec2 CANVAS_PIVOT_SIZE = {4, 4};
|
||||
|
||||
const f32 CANVAS_AXIS_VERTICES[] =
|
||||
{
|
||||
-CANVAS_LINE_LENGTH, 0.0f,
|
||||
CANVAS_LINE_LENGTH, 0.0f,
|
||||
0.0f, -CANVAS_LINE_LENGTH,
|
||||
0.0f, CANVAS_LINE_LENGTH
|
||||
-CANVAS_LINE_LENGTH, 0.0f,
|
||||
CANVAS_LINE_LENGTH, 0.0f,
|
||||
0.0f, -CANVAS_LINE_LENGTH,
|
||||
0.0f, CANVAS_LINE_LENGTH
|
||||
};
|
||||
|
||||
struct Canvas
|
||||
{
|
||||
GLuint fbo;
|
||||
GLuint rbo;
|
||||
GLuint texture;
|
||||
GLuint textureEBO;
|
||||
GLuint textureVAO;
|
||||
GLuint textureVBO;
|
||||
vec2 size;
|
||||
GLuint fbo{};
|
||||
GLuint rbo{};
|
||||
GLuint axisVAO{};
|
||||
GLuint axisVBO{};
|
||||
GLuint rectVAO{};
|
||||
GLuint rectVBO{};
|
||||
GLuint gridVAO{};
|
||||
GLuint gridVBO{};
|
||||
GLuint texture{};
|
||||
GLuint textureEBO{};
|
||||
GLuint textureVAO{};
|
||||
GLuint textureVBO{};
|
||||
vec2 size{};
|
||||
};
|
||||
|
||||
void canvas_init(Canvas* self, vec2 size);
|
||||
void canvas_init(Canvas* self);
|
||||
mat4 canvas_transform_get(Canvas* self, vec2& pan, f32& zoom, OriginType origin);
|
||||
void canvas_clear(vec4& color);
|
||||
void canvas_bind(Canvas* self);
|
||||
void canvas_viewport_set(Canvas* self);
|
||||
void canvas_unbind(void);
|
||||
void canvas_texture_set(Canvas* self);
|
||||
void canvas_grid_draw(Canvas* self, GLuint& shader, mat4& transform, f32& zoom, ivec2& size, ivec2& offset, vec4& color);
|
||||
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color);
|
||||
void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform, const vec4& color);
|
||||
void canvas_free(Canvas* self);
|
||||
void canvas_draw(Canvas* self);
|
||||
|
||||
mat4 canvas_mvp_get
|
||||
(
|
||||
mat4& transform,
|
||||
vec2 size,
|
||||
vec2 position = {0.0f, 0.0f},
|
||||
vec2 pivot = {0.0f, 0.0f},
|
||||
f32 rotation = {0.0f},
|
||||
vec2 scale = {1.0f, 1.0f},
|
||||
vec2 pivotAlt = {0.0f, 0.0f},
|
||||
f32 rotationAlt = {0.0f}
|
||||
);
|
||||
|
||||
void canvas_texture_draw
|
||||
(
|
||||
Canvas* self,
|
||||
GLuint& shader,
|
||||
GLuint& texture,
|
||||
mat4& transform,
|
||||
const f32* vertices = GL_UV_VERTICES,
|
||||
vec4 tint = COLOR_OPAQUE,
|
||||
vec3 colorOffset = COLOR_OFFSET_NONE
|
||||
);
|
@@ -47,17 +47,6 @@ static void _clipboard_item_remove(ClipboardItem* self, Anm2* anm2)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_EVENT:
|
||||
{
|
||||
Anm2EventWithID eventWithID = std::get<Anm2EventWithID>(self->data);
|
||||
|
||||
for (auto & [id, event] : anm2->events)
|
||||
{
|
||||
if (id == eventWithID.id)
|
||||
anm2->events.erase(eventWithID.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -81,7 +70,7 @@ static void _clipboard_item_paste(ClipboardItem* self, ClipboardLocation* locati
|
||||
if (!animation || !anm2Item) break;
|
||||
|
||||
s32 insertIndex = (reference->itemType == ANM2_TRIGGERS) ?
|
||||
reference->frameIndex : MAX(reference->frameIndex, (s32)anm2Item->frames.size());
|
||||
reference->frameIndex : std::max(reference->frameIndex, (s32)anm2Item->frames.size());
|
||||
|
||||
anm2Item->frames.insert(anm2Item->frames.begin() + insertIndex, frameWithReference->frame);
|
||||
|
||||
@@ -95,23 +84,11 @@ static void _clipboard_item_paste(ClipboardItem* self, ClipboardLocation* locati
|
||||
if (std::holds_alternative<s32>(*location))
|
||||
index = std::get<s32>(*location);
|
||||
|
||||
index = CLAMP(index, 0, (s32)anm2->animations.size());
|
||||
index = std::clamp(index, 0, (s32)anm2->animations.size());
|
||||
|
||||
map_insert_shift(anm2->animations, index, std::get<Anm2AnimationWithID>(self->data).animation);
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_EVENT:
|
||||
{
|
||||
s32 index = 0;
|
||||
|
||||
if (std::holds_alternative<s32>(*location))
|
||||
index = std::get<s32>(*location);
|
||||
|
||||
index = CLAMP(index, 0, (s32)anm2->events.size());
|
||||
|
||||
map_insert_shift(anm2->events, index, std::get<Anm2EventWithID>(self->data).event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ enum ClipboardItemType
|
||||
CLIPBOARD_NONE,
|
||||
CLIPBOARD_FRAME,
|
||||
CLIPBOARD_ANIMATION,
|
||||
CLIPBOARD_EVENT
|
||||
};
|
||||
|
||||
struct ClipboardItem
|
||||
@@ -22,9 +21,6 @@ struct ClipboardItem
|
||||
|
||||
ClipboardItem(const Anm2AnimationWithID& anim)
|
||||
: data(anim), type(CLIPBOARD_ANIMATION) {}
|
||||
|
||||
ClipboardItem(const Anm2EventWithID& event)
|
||||
: data(event), type(CLIPBOARD_EVENT) {}
|
||||
};
|
||||
|
||||
using ClipboardLocation = std::variant<std::monostate, Anm2Reference, s32>;
|
||||
|
@@ -14,9 +14,13 @@ static void _dialog_callback(void* userdata, const char* const* filelist, s32 fi
|
||||
{
|
||||
self->path = filelist[0];
|
||||
self->isSelected = true;
|
||||
self->selectedFilter = filter;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->isSelected = false;
|
||||
self->selectedFilter = INDEX_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window)
|
||||
@@ -51,8 +55,10 @@ void dialog_png_replace(Dialog* self)
|
||||
self->type = DIALOG_PNG_REPLACE;
|
||||
}
|
||||
|
||||
void dialog_tick(Dialog* self)
|
||||
void dialog_update(Dialog* self)
|
||||
{
|
||||
self->isJustSelected = false;
|
||||
|
||||
if (self->isSelected)
|
||||
{
|
||||
Texture texture;
|
||||
@@ -73,7 +79,7 @@ void dialog_tick(Dialog* self)
|
||||
case DIALOG_PNG_OPEN:
|
||||
id = map_next_id_get(self->resources->textures);
|
||||
self->anm2->spritesheets[id] = Anm2Spritesheet{};
|
||||
self->path = self->anm2->spritesheets[id].path;
|
||||
self->anm2->spritesheets[id].path = self->path;
|
||||
resources_texture_init(self->resources, self->path, id);
|
||||
break;
|
||||
case DIALOG_PNG_REPLACE:
|
||||
@@ -85,8 +91,23 @@ void dialog_tick(Dialog* self)
|
||||
break;
|
||||
}
|
||||
|
||||
self->lastType = self->type;
|
||||
self->lastPath = self->path;
|
||||
self->type = DIALOG_NONE;
|
||||
self->path.clear();
|
||||
|
||||
self->isJustSelected = true;
|
||||
self->isSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dialog_reset(Dialog* self)
|
||||
{
|
||||
self->lastType = DIALOG_NONE;
|
||||
self->type = DIALOG_NONE;
|
||||
self->lastPath.clear();
|
||||
self->path.clear();
|
||||
self->isJustSelected = false;
|
||||
self->isSelected = false;
|
||||
}
|
@@ -31,9 +31,13 @@ struct Dialog
|
||||
Resources* resources = nullptr;
|
||||
SDL_Window* window = nullptr;
|
||||
std::string path{};
|
||||
std::string lastPath{};
|
||||
s32 replaceID = ID_NONE;
|
||||
s32 selectedFilter{};
|
||||
DialogType type = DIALOG_NONE;
|
||||
DialogType lastType = DIALOG_NONE;
|
||||
bool isSelected = false;
|
||||
bool isJustSelected = false;
|
||||
};
|
||||
|
||||
void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window);
|
||||
@@ -42,4 +46,5 @@ void dialog_png_open(Dialog* self);
|
||||
void dialog_png_replace(Dialog* self);
|
||||
void dialog_anm2_save(Dialog* self);
|
||||
void dialog_frame_directory_open(Dialog* self);
|
||||
void dialog_tick(Dialog* self);
|
||||
void dialog_update(Dialog* self);
|
||||
void dialog_reset(Dialog* self);
|
291
src/editor.cpp
291
src/editor.cpp
@@ -2,47 +2,6 @@
|
||||
|
||||
#include "editor.h"
|
||||
|
||||
static s32 _editor_grid_set(Editor* self)
|
||||
{
|
||||
std::vector<f32> vertices;
|
||||
|
||||
s32 verticalLineCount = (s32)(EDITOR_SIZE.x / MIN(self->settings->editorGridSizeX, EDITOR_GRID_MIN));
|
||||
s32 horizontalLineCount = (s32)(EDITOR_SIZE.y / MIN(self->settings->editorGridSizeY, EDITOR_GRID_MIN));
|
||||
|
||||
// Vertical
|
||||
for (s32 i = 0; i <= verticalLineCount; i++)
|
||||
{
|
||||
s32 x = i * self->settings->editorGridSizeX - self->settings->editorGridOffsetX;
|
||||
f32 normX = (2.0f * x) / EDITOR_SIZE.x - 1.0f;
|
||||
|
||||
vertices.push_back(normX);
|
||||
vertices.push_back(-1.0f);
|
||||
vertices.push_back(normX);
|
||||
vertices.push_back(1.0f);
|
||||
}
|
||||
|
||||
// Horizontal
|
||||
for (s32 i = 0; i <= horizontalLineCount; i++)
|
||||
{
|
||||
s32 y = i * self->settings->editorGridSizeY - self->settings->editorGridOffsetY;
|
||||
f32 normY = (2.0f * y) / EDITOR_SIZE.y - 1.0f;
|
||||
|
||||
vertices.push_back(-1.0f);
|
||||
vertices.push_back(normY);
|
||||
vertices.push_back(1.0f);
|
||||
vertices.push_back(normY);
|
||||
}
|
||||
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->gridVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(f32), vertices.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
return (s32)vertices.size();
|
||||
}
|
||||
|
||||
void editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings)
|
||||
{
|
||||
self->anm2 = anm2;
|
||||
@@ -50,253 +9,53 @@ void editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources*
|
||||
self->resources = resources;
|
||||
self->settings = settings;
|
||||
|
||||
// Framebuffer + texture
|
||||
glGenFramebuffers(1, &self->fbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
|
||||
glGenTextures(1, &self->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, self->texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (s32)EDITOR_SIZE.x, (s32)EDITOR_SIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture, 0);
|
||||
|
||||
glGenRenderbuffers(1, &self->rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, self->rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (s32)EDITOR_SIZE.x, (s32)EDITOR_SIZE.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Grid
|
||||
glGenVertexArrays(1, &self->gridVAO);
|
||||
glGenBuffers(1, &self->gridVBO);
|
||||
|
||||
// Border
|
||||
glGenVertexArrays(1, &self->borderVAO);
|
||||
glGenBuffers(1, &self->borderVBO);
|
||||
|
||||
glBindVertexArray(self->borderVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->borderVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_VERTICES), GL_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
// Texture
|
||||
glGenVertexArrays(1, &self->textureVAO);
|
||||
glGenBuffers(1, &self->textureVBO);
|
||||
glGenBuffers(1, &self->textureEBO);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(f32) * 4 * 4, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW);
|
||||
|
||||
// Position attribute
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0);
|
||||
|
||||
// UV position attribute
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32)));
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
_editor_grid_set(self);
|
||||
canvas_init(&self->canvas);
|
||||
}
|
||||
|
||||
void editor_draw(Editor* self)
|
||||
{
|
||||
GLuint shaderLine = self->resources->shaders[SHADER_LINE];
|
||||
GLuint shaderLineDotted = self->resources->shaders[SHADER_LINE_DOTTED];
|
||||
GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE];
|
||||
|
||||
f32 zoomFactor = PERCENT_TO_UNIT(self->settings->editorZoom);
|
||||
ivec2& gridSize = self->settings->editorGridSize;
|
||||
ivec2& gridOffset = self->settings->editorGridOffset;
|
||||
vec4& gridColor = self->settings->editorGridColor;
|
||||
GLuint& shaderLine = self->resources->shaders[SHADER_LINE];
|
||||
GLuint& shaderTexture = self->resources->shaders[SHADER_TEXTURE];
|
||||
mat4 transform = canvas_transform_get(&self->canvas, self->settings->editorPan, self->settings->editorZoom, ORIGIN_TOP_LEFT);
|
||||
|
||||
// Get normalized panning
|
||||
glm::vec2 ndcPan = glm::vec2(-self->settings->editorPanX / (EDITOR_SIZE.x / 2.0f), -self->settings->editorPanY / (EDITOR_SIZE.y / 2.0f));
|
||||
canvas_texture_set(&self->canvas);
|
||||
|
||||
canvas_bind(&self->canvas);
|
||||
canvas_viewport_set(&self->canvas);
|
||||
canvas_clear(self->settings->editorBackgroundColor);
|
||||
|
||||
glm::mat4 editorTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f));
|
||||
editorTransform = glm::scale(editorTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f));
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
glViewport(0, 0, EDITOR_SIZE.x, EDITOR_SIZE.y);
|
||||
|
||||
glClearColor
|
||||
(
|
||||
self->settings->editorBackgroundColorR,
|
||||
self->settings->editorBackgroundColorG,
|
||||
self->settings->editorBackgroundColorB,
|
||||
self->settings->editorBackgroundColorA
|
||||
);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Drawing the selected spritesheet
|
||||
if (self->spritesheetID > -1)
|
||||
if (self->spritesheetID != ID_NONE)
|
||||
{
|
||||
Texture* texture = &self->resources->textures[self->spritesheetID];
|
||||
Texture texture = self->resources->textures[self->spritesheetID];
|
||||
mat4 mvp = canvas_mvp_get(transform, texture.size);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, mvp);
|
||||
|
||||
glm::mat4 spritesheetTransform = editorTransform;
|
||||
glm::vec2 ndcScale = glm::vec2(texture->size.x, texture->size.y) / (EDITOR_SIZE * 0.5f);
|
||||
|
||||
spritesheetTransform = glm::scale(spritesheetTransform, glm::vec3(ndcScale, 1.0f));
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_UV_VERTICES), GL_UV_VERTICES, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(COLOR_OPAQUE));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(spritesheetTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
|
||||
// Border around the spritesheet
|
||||
if (self->settings->editorIsBorder)
|
||||
{
|
||||
glUseProgram(shaderLineDotted);
|
||||
|
||||
glBindVertexArray(self->borderVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(spritesheetTransform));
|
||||
glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(EDITOR_BORDER_TINT));
|
||||
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
canvas_rect_draw(&self->canvas, shaderLine, mvp, EDITOR_BORDER_COLOR);
|
||||
|
||||
Anm2Frame* frame = (Anm2Frame*)anm2_frame_from_reference(self->anm2, self->reference);
|
||||
|
||||
// Drawing the frame's crop and pivot
|
||||
|
||||
if (frame)
|
||||
{
|
||||
// Crop
|
||||
glm::mat4 rectTransform = editorTransform;
|
||||
|
||||
glm::vec2 rectNDCPos = frame->crop / (EDITOR_SIZE / 2.0f);
|
||||
glm::vec2 rectNDCScale = frame->size / (EDITOR_SIZE / 2.0f);
|
||||
|
||||
rectTransform = glm::translate(rectTransform, glm::vec3(rectNDCPos, 0.0f));
|
||||
rectTransform = glm::scale(rectTransform, glm::vec3(rectNDCScale, 1.0f));
|
||||
|
||||
glUseProgram(shaderLineDotted);
|
||||
|
||||
glBindVertexArray(self->borderVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(rectTransform));
|
||||
glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(EDITOR_FRAME_TINT));
|
||||
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
|
||||
// Pivot
|
||||
glm::mat4 pivotTransform = editorTransform;
|
||||
glm::vec2 pivotNDCPos = ((frame->crop + frame->pivot) - (EDITOR_PIVOT_SIZE / 2.0f)) / (EDITOR_SIZE / 2.0f);
|
||||
glm::vec2 pivotNDCScale = EDITOR_PIVOT_SIZE / (EDITOR_SIZE / 2.0f);
|
||||
|
||||
pivotTransform = glm::translate(pivotTransform, glm::vec3(pivotNDCPos, 0.0f));
|
||||
pivotTransform = glm::scale(pivotTransform, glm::vec3(pivotNDCScale, 1.0f));
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
mvp = canvas_mvp_get(transform, frame->size, frame->crop);
|
||||
canvas_rect_draw(&self->canvas, shaderLine, mvp, EDITOR_FRAME_COLOR);
|
||||
|
||||
mvp = canvas_mvp_get(transform, CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f);
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(EDITOR_FRAME_TINT));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(pivotTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, mvp, vertices, EDITOR_PIVOT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
// Grid
|
||||
if (self->settings->editorIsGrid)
|
||||
{
|
||||
static ivec2 previousGridSize = {-1, -1};
|
||||
static ivec2 previousGridOffset = {-1, -1};
|
||||
static s32 gridVertexCount = -1;
|
||||
canvas_grid_draw(&self->canvas, shaderLine, transform, self->settings->editorZoom, gridSize, gridOffset, gridColor);
|
||||
|
||||
glm::mat4 gridTransform = editorTransform;
|
||||
glm::vec2 gridNDCPos = (EDITOR_SIZE / 2.0f) / (EDITOR_SIZE / 2.0f);
|
||||
|
||||
gridTransform = glm::translate(gridTransform, glm::vec3(gridNDCPos, 0.0f));
|
||||
|
||||
ivec2 gridSize = ivec2(self->settings->editorGridSizeX, self->settings->editorGridSizeY);
|
||||
ivec2 gridOffset = ivec2(self->settings->editorGridOffsetX, self->settings->editorGridOffsetY);
|
||||
|
||||
if (previousGridSize != gridSize || previousGridOffset != gridOffset)
|
||||
{
|
||||
gridVertexCount = _editor_grid_set(self);
|
||||
previousGridSize = gridSize;
|
||||
previousGridOffset = gridOffset;
|
||||
}
|
||||
|
||||
glUseProgram(shaderLine);
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(gridTransform));
|
||||
|
||||
glUniform4f
|
||||
(
|
||||
glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR),
|
||||
self->settings->editorGridColorR, self->settings->editorGridColorG, self->settings->editorGridColorB, self->settings->editorGridColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, gridVertexCount);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void editor_tick(Editor* self)
|
||||
{
|
||||
self->settings->editorZoom = CLAMP(self->settings->editorZoom, EDITOR_ZOOM_MIN, EDITOR_ZOOM_MAX);
|
||||
canvas_unbind();
|
||||
}
|
||||
|
||||
void editor_free(Editor* self)
|
||||
{
|
||||
glDeleteTextures(1, &self->texture);
|
||||
glDeleteFramebuffers(1, &self->fbo);
|
||||
glDeleteRenderbuffers(1, &self->rbo);
|
||||
canvas_free(&self->canvas);
|
||||
}
|
19
src/editor.h
19
src/editor.h
@@ -1,23 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "anm2.h"
|
||||
#include "canvas.h"
|
||||
#include "resources.h"
|
||||
#include "settings.h"
|
||||
#include "canvas.h"
|
||||
|
||||
#define EDITOR_ZOOM_MIN 1
|
||||
#define EDITOR_ZOOM_MAX 1000
|
||||
#define EDITOR_ZOOM_STEP 25
|
||||
#define EDITOR_ZOOM_MIN 1.0f
|
||||
#define EDITOR_ZOOM_MAX 1000.0f
|
||||
#define EDITOR_ZOOM_STEP 25.0
|
||||
#define EDITOR_GRID_MIN 1
|
||||
#define EDITOR_GRID_MAX 1000
|
||||
#define EDITOR_GRID_OFFSET_MIN 0
|
||||
#define EDITOR_GRID_OFFSET_MAX 100
|
||||
|
||||
const vec2 EDITOR_SIZE = {2000, 2000};
|
||||
const vec2 EDITOR_PIVOT_SIZE = {4, 4};
|
||||
const vec4 EDITOR_TEXTURE_TINT = COLOR_OPAQUE;
|
||||
const vec4 EDITOR_BORDER_TINT = COLOR_OPAQUE;
|
||||
const vec4 EDITOR_FRAME_TINT = COLOR_RED;
|
||||
static const vec4 EDITOR_BORDER_COLOR = COLOR_OPAQUE;
|
||||
static const vec4 EDITOR_FRAME_COLOR = COLOR_RED;
|
||||
static const vec4 EDITOR_PIVOT_COLOR = COLOR_PINK;
|
||||
|
||||
struct Editor
|
||||
{
|
||||
@@ -25,6 +23,7 @@ struct Editor
|
||||
Anm2Reference* reference = nullptr;
|
||||
Resources* resources = nullptr;
|
||||
Settings* settings = nullptr;
|
||||
Canvas canvas;
|
||||
GLuint fbo;
|
||||
GLuint rbo;
|
||||
GLuint gridVAO;
|
||||
@@ -39,7 +38,5 @@ struct Editor
|
||||
};
|
||||
|
||||
void editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings);
|
||||
|
||||
void editor_draw(Editor* self);
|
||||
void editor_tick(Editor* self);
|
||||
void editor_free(Editor* self);
|
1354
src/imgui.cpp
1354
src/imgui.cpp
File diff suppressed because it is too large
Load Diff
682
src/imgui.h
682
src/imgui.h
File diff suppressed because it is too large
Load Diff
564
src/preview.cpp
564
src/preview.cpp
@@ -2,59 +2,6 @@
|
||||
|
||||
#include "preview.h"
|
||||
|
||||
static void _preview_axis_set(Preview* self)
|
||||
{
|
||||
glBindVertexArray(self->axisVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->axisVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(CANVAS_AXIS_VERTICES), CANVAS_AXIS_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
static s32 _preview_grid_set(Preview* self)
|
||||
{
|
||||
std::vector<f32> vertices;
|
||||
|
||||
s32 verticalLineCount = (s32)(PREVIEW_SIZE.x / MIN(self->settings->previewGridSizeX, PREVIEW_GRID_MIN));
|
||||
s32 horizontalLineCount = (s32)(PREVIEW_SIZE.y / MIN(self->settings->previewGridSizeY, PREVIEW_GRID_MIN));
|
||||
|
||||
// Vertical
|
||||
for (s32 i = 0; i <= verticalLineCount; i++)
|
||||
{
|
||||
s32 x = i * self->settings->previewGridSizeX - self->settings->previewGridOffsetX;
|
||||
f32 normX = (2.0f * x) / PREVIEW_SIZE.x - 1.0f;
|
||||
|
||||
vertices.push_back(normX);
|
||||
vertices.push_back(-1.0f);
|
||||
vertices.push_back(normX);
|
||||
vertices.push_back(1.0f);
|
||||
}
|
||||
|
||||
// Horizontal
|
||||
for (s32 i = 0; i <= horizontalLineCount; i++)
|
||||
{
|
||||
s32 y = i * self->settings->previewGridSizeY - self->settings->previewGridOffsetY;
|
||||
f32 normY = (2.0f * y) / PREVIEW_SIZE.y - 1.0f;
|
||||
|
||||
vertices.push_back(-1.0f);
|
||||
vertices.push_back(normY);
|
||||
vertices.push_back(1.0f);
|
||||
vertices.push_back(normY);
|
||||
}
|
||||
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->gridVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(f32), vertices.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
return (s32)vertices.size();
|
||||
}
|
||||
|
||||
void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings)
|
||||
{
|
||||
self->anm2 = anm2;
|
||||
@@ -62,87 +9,19 @@ void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources
|
||||
self->resources = resources;
|
||||
self->settings = settings;
|
||||
|
||||
// Framebuffer + texture
|
||||
glGenFramebuffers(1, &self->fbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
|
||||
glGenTextures(1, &self->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, self->texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture, 0);
|
||||
|
||||
glGenRenderbuffers(1, &self->rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, self->rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Axis
|
||||
glGenVertexArrays(1, &self->axisVAO);
|
||||
glGenBuffers(1, &self->axisVBO);
|
||||
|
||||
// Grid
|
||||
glGenVertexArrays(1, &self->gridVAO);
|
||||
glGenBuffers(1, &self->gridVBO);
|
||||
|
||||
// Rect
|
||||
glGenVertexArrays(1, &self->rectVAO);
|
||||
glGenBuffers(1, &self->rectVBO);
|
||||
|
||||
glBindVertexArray(self->rectVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_VERTICES), GL_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
|
||||
|
||||
// Texture
|
||||
glGenVertexArrays(1, &self->textureVAO);
|
||||
glGenBuffers(1, &self->textureVBO);
|
||||
glGenBuffers(1, &self->textureEBO);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(f32) * 4 * 4, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW);
|
||||
|
||||
// Position attribute
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0);
|
||||
|
||||
// UV attribute
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32)));
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
_preview_axis_set(self);
|
||||
_preview_grid_set(self);
|
||||
canvas_init(&self->canvas);
|
||||
}
|
||||
|
||||
void preview_tick(Preview* self)
|
||||
{
|
||||
self->settings->previewZoom = CLAMP(self->settings->previewZoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX);
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference);
|
||||
|
||||
// If animation is valid, manage playback
|
||||
if (animation)
|
||||
{
|
||||
if (self->isPlaying)
|
||||
{
|
||||
self->time += (f32)self->anm2->fps / TICK_RATE;
|
||||
|
||||
// If looping, return back to 0; if not, stop at length
|
||||
if (self->time >= (f32)animation->frameNum - 1)
|
||||
{
|
||||
if (self->settings->playbackIsLoop && !self->isRecording)
|
||||
@@ -152,414 +31,181 @@ void preview_tick(Preview* self)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to clamp time within appropriate range
|
||||
if (!self->isPlaying)
|
||||
self->time = CLAMP(self->time, 0.0f, (f32)animation->frameNum - 1);
|
||||
self->time = std::clamp(self->time, 0.0f, (f32)animation->frameNum - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void preview_draw(Preview* self)
|
||||
{
|
||||
GLuint shaderLine = self->resources->shaders[SHADER_LINE];
|
||||
GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE];
|
||||
static bool isRecordThisFrame = false;
|
||||
static f32 recordFrameTimeNext = 0.0f;
|
||||
static s32 recordFrameIndex = 0;
|
||||
|
||||
f32 zoomFactor = PERCENT_TO_UNIT(self->settings->previewZoom);
|
||||
glm::vec2 ndcPan = glm::vec2(-self->settings->previewPanX / (PREVIEW_SIZE.x / 2.0f), -self->settings->previewPanY / (PREVIEW_SIZE.y / 2.0f));
|
||||
glm::mat4 previewTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f));
|
||||
previewTransform = glm::scale(previewTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f));
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
|
||||
glViewport(0, 0, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y);
|
||||
|
||||
glClearColor
|
||||
(
|
||||
self->settings->previewBackgroundColorR,
|
||||
self->settings->previewBackgroundColorG,
|
||||
self->settings->previewBackgroundColorB,
|
||||
self->settings->previewBackgroundColorA
|
||||
);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Grid
|
||||
if (self->settings->previewIsGrid)
|
||||
{
|
||||
static ivec2 previousGridSize = {-1, -1};
|
||||
static ivec2 previousGridOffset = {-1, -1};
|
||||
static s32 gridVertexCount = -1;
|
||||
ivec2 gridSize = ivec2(self->settings->previewGridSizeX, self->settings->previewGridSizeY);
|
||||
ivec2 gridOffset = ivec2(self->settings->previewGridOffsetX, self->settings->previewGridOffsetY);
|
||||
|
||||
if (previousGridSize != gridSize || previousGridOffset != gridOffset)
|
||||
{
|
||||
gridVertexCount = _preview_grid_set(self);
|
||||
previousGridSize = gridSize;
|
||||
previousGridOffset = gridOffset;
|
||||
}
|
||||
|
||||
glUseProgram(shaderLine);
|
||||
glBindVertexArray(self->gridVAO);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(previewTransform));
|
||||
|
||||
glUniform4f
|
||||
(
|
||||
glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR),
|
||||
self->settings->previewGridColorR, self->settings->previewGridColorG, self->settings->previewGridColorB, self->settings->previewGridColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, gridVertexCount);
|
||||
ivec2& gridSize = self->settings->previewGridSize;
|
||||
ivec2& gridOffset = self->settings->previewGridOffset;
|
||||
vec4& gridColor = self->settings->previewGridColor;
|
||||
f32& zoom = self->settings->previewZoom;
|
||||
GLuint& shaderLine = self->resources->shaders[SHADER_LINE];
|
||||
GLuint& shaderTexture = self->resources->shaders[SHADER_TEXTURE];
|
||||
mat4 transform = canvas_transform_get(&self->canvas, self->settings->previewPan, self->settings->previewZoom, ORIGIN_CENTER);
|
||||
|
||||
canvas_texture_set(&self->canvas);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
canvas_bind(&self->canvas);
|
||||
canvas_viewport_set(&self->canvas);
|
||||
canvas_clear(self->settings->previewBackgroundColor);
|
||||
|
||||
if (self->settings->previewIsGrid)
|
||||
canvas_grid_draw(&self->canvas, shaderLine, transform, zoom, gridSize, gridOffset, gridColor);
|
||||
|
||||
// Axes
|
||||
if (self->settings->previewIsAxis)
|
||||
{
|
||||
glUseProgram(shaderLine);
|
||||
glBindVertexArray(self->axisVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(previewTransform));
|
||||
|
||||
glUniform4f
|
||||
(
|
||||
glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR),
|
||||
self->settings->previewAxisColorR, self->settings->previewAxisColorG, self->settings->previewAxisColorB, self->settings->previewAxisColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
|
||||
glUniform4f
|
||||
(
|
||||
glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR),
|
||||
self->settings->previewAxisColorR, self->settings->previewAxisColorG, self->settings->previewAxisColorB, self->settings->previewAxisColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 2, 2);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
canvas_axes_draw(&self->canvas, shaderLine, transform, self->settings->previewAxisColor);
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference);
|
||||
s32& animationID = self->reference->animationID;
|
||||
|
||||
// Animation
|
||||
if (animation)
|
||||
{
|
||||
Anm2Frame rootFrame;
|
||||
Anm2Frame frame;
|
||||
anm2_frame_from_time(self->anm2, &rootFrame, Anm2Reference{animationID, ANM2_ROOT, 0, 0}, self->time);
|
||||
Anm2Frame root;
|
||||
mat4 rootModel = mat4(1.0f);
|
||||
|
||||
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationID, ANM2_ROOT}, self->time);
|
||||
|
||||
if (self->settings->previewIsRootTransform)
|
||||
rootModel = quad_parent_model_get(root.position, vec2(0.0f), root.rotation, PERCENT_TO_UNIT(root.scale));
|
||||
|
||||
// Root
|
||||
if (animation->rootAnimation.isVisible && root.isVisible)
|
||||
{
|
||||
mat4 model = quad_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, root.rotation, PERCENT_TO_UNIT(root.scale));
|
||||
mat4 rootTransform = transform * model;
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_TARGET);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, rootTransform, vertices, PREVIEW_ROOT_COLOR);
|
||||
}
|
||||
|
||||
// Layers
|
||||
for (auto [i, id] : self->anm2->layerMap)
|
||||
{
|
||||
Anm2Frame frame;
|
||||
Anm2Item& layerAnimation = animation->layerAnimations[id];
|
||||
|
||||
if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id, 0}, self->time);
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id}, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
Texture* texture = &self->resources->textures[self->anm2->layers[id].spritesheetID];
|
||||
Texture texture = self->resources->textures[self->anm2->layers[id].spritesheetID];
|
||||
|
||||
if (texture->isInvalid)
|
||||
if (texture.isInvalid)
|
||||
continue;
|
||||
|
||||
glm::mat4 layerTransform = previewTransform;
|
||||
|
||||
glm::vec2 position = self->settings->previewIsRootTransform ?
|
||||
(frame.position + rootFrame.position) : frame.position;
|
||||
|
||||
glm::vec2 scale = self->settings->previewIsRootTransform ?
|
||||
PERCENT_TO_UNIT(frame.scale) * PERCENT_TO_UNIT(rootFrame.scale) : PERCENT_TO_UNIT(frame.scale);
|
||||
|
||||
glm::vec2 ndcPos = position / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcPivotOffset = (frame.pivot * scale) / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = (frame.size * scale) / (PREVIEW_SIZE / 2.0f);
|
||||
f32 rotation = frame.rotation;
|
||||
|
||||
layerTransform = glm::translate(layerTransform, glm::vec3(ndcPos - ndcPivotOffset, 0.0f));
|
||||
layerTransform = glm::translate(layerTransform, glm::vec3(ndcPivotOffset, 0.0f));
|
||||
layerTransform = glm::rotate(layerTransform, glm::radians(rotation), glm::vec3(0, 0, 1));
|
||||
layerTransform = glm::translate(layerTransform, glm::vec3(-ndcPivotOffset, 0.0f));
|
||||
layerTransform = glm::scale(layerTransform, glm::vec3(ndcScale, 1.0f));
|
||||
|
||||
glm::vec2 uvMin = frame.crop / glm::vec2(texture->size);
|
||||
glm::vec2 uvMax = (frame.crop + frame.size) / glm::vec2(texture->size);
|
||||
|
||||
vec2 uvMin = frame.crop / vec2(texture.size);
|
||||
vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size);
|
||||
f32 vertices[] = UV_VERTICES(uvMin, uvMax);
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->id);
|
||||
mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, frame.rotation, PERCENT_TO_UNIT(frame.scale));
|
||||
mat4 layerTransform = transform * (rootModel * model);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, (f32*)value_ptr(frame.tintRGBA));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, (f32*)value_ptr(frame.offsetRGB));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(layerTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, layerTransform, vertices, frame.tintRGBA, frame.offsetRGB);
|
||||
|
||||
// Root target
|
||||
if (animation->rootAnimation.isVisible && rootFrame.isVisible)
|
||||
{
|
||||
glm::mat4 rootTransform = previewTransform;
|
||||
glm::vec2 ndcPos = (rootFrame.position - (PREVIEW_TARGET_SIZE / 2.0f)) / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = PREVIEW_TARGET_SIZE / (PREVIEW_SIZE / 2.0f);
|
||||
if (self->settings->previewIsBorder)
|
||||
canvas_rect_draw(&self->canvas, shaderLine, layerTransform, PREVIEW_BORDER_COLOR);
|
||||
|
||||
rootTransform = glm::translate(rootTransform, glm::vec3(ndcPos, 0.0f));
|
||||
rootTransform = glm::scale(rootTransform, glm::vec3(ndcScale, 1.0f));
|
||||
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_TARGET);
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_ROOT_TINT));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(rootTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
// Layer pivots
|
||||
if (self->settings->previewIsShowPivot)
|
||||
{
|
||||
// Layers (Reversed)
|
||||
for (auto & [id, layerAnimation] : animation->layerAnimations)
|
||||
if (self->settings->previewIsShowPivot)
|
||||
{
|
||||
if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id, 0}, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
glm::mat4 pivotTransform = previewTransform;
|
||||
|
||||
glm::vec2 position = self->settings->previewIsRootTransform
|
||||
? (frame.position + rootFrame.position) : frame.position;
|
||||
|
||||
glm::vec2 scale = self->settings->previewIsRootTransform ?
|
||||
PERCENT_TO_UNIT(frame.scale) * PERCENT_TO_UNIT(rootFrame.scale) : PERCENT_TO_UNIT(frame.scale);
|
||||
|
||||
glm::vec2 ndcPos = (position - (PREVIEW_PIVOT_SIZE / 2.0f)) / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = PREVIEW_PIVOT_SIZE / (PREVIEW_SIZE / 2.0f);
|
||||
|
||||
pivotTransform = glm::translate(pivotTransform, glm::vec3(ndcPos, 0.0f));
|
||||
pivotTransform = glm::scale(pivotTransform, glm::vec3(ndcScale, 1.0f));
|
||||
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT);
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_PIVOT_TINT));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(pivotTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glUseProgram(0);
|
||||
mat4 pivotModel = quad_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale));
|
||||
mat4 pivotTransform = transform * (rootModel * pivotModel);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, PREVIEW_PIVOT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
// Null target/rect
|
||||
for (auto & [id, nullAnimation] : animation->nullAnimations)
|
||||
// Nulls
|
||||
for (auto& [id, nullAnimation] : animation->nullAnimations)
|
||||
{
|
||||
if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id, 0}, self->time);
|
||||
Anm2Frame frame;
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id}, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
Anm2Null* null = &self->anm2->nulls[id];
|
||||
Anm2Null null = self->anm2->nulls[id];
|
||||
|
||||
glm::mat4 nullTransform = previewTransform;
|
||||
vec4 color = (self->reference->itemType == ANM2_NULL && self->reference->itemID == id) ?
|
||||
PREVIEW_NULL_SELECTED_COLOR :
|
||||
PREVIEW_NULL_COLOR;
|
||||
|
||||
TextureType textureType = null->isShowRect ? TEXTURE_UNINTERPOLATED : TEXTURE_TARGET;
|
||||
glm::vec2 size = null->isShowRect ? PREVIEW_POINT_SIZE : PREVIEW_TARGET_SIZE;
|
||||
glm::vec2 pos = self->settings->previewIsRootTransform ? frame.position + (rootFrame.position) - (size / 2.0f) : frame.position - (size / 2.0f);
|
||||
vec2 size = null.isShowRect ? CANVAS_PIVOT_SIZE : PREVIEW_TARGET_SIZE;
|
||||
TextureType texture = null.isShowRect ? TEXTURE_SQUARE : TEXTURE_TARGET;
|
||||
|
||||
mat4 model = quad_model_get(size, frame.position, size * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale));
|
||||
mat4 nullTransform = transform * (rootModel * model);
|
||||
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(texture);
|
||||
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, nullTransform, vertices, color);
|
||||
|
||||
glm::vec2 ndcPos = pos / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = size / (PREVIEW_SIZE / 2.0f);
|
||||
|
||||
nullTransform = glm::translate(nullTransform, glm::vec3(ndcPos, 0.0f));
|
||||
nullTransform = glm::scale(nullTransform, glm::vec3(ndcScale, 1.0f));
|
||||
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(textureType);
|
||||
|
||||
glUseProgram(shaderTexture);
|
||||
|
||||
glBindVertexArray(self->textureVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id);
|
||||
|
||||
glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0);
|
||||
glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_NULL_TINT));
|
||||
glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(nullTransform));
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glUseProgram(0);
|
||||
|
||||
// Null rect
|
||||
if (null->isShowRect)
|
||||
if (null.isShowRect)
|
||||
{
|
||||
glm::mat4 rectTransform = previewTransform;
|
||||
|
||||
glm::vec2 rectPos = pos - (PREVIEW_NULL_RECT_SIZE / 2.0f);
|
||||
glm::vec2 rectNDCPos = rectPos / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 rectNDCScale = PREVIEW_NULL_RECT_SIZE / (PREVIEW_SIZE / 2.0f);
|
||||
|
||||
rectTransform = glm::translate(rectTransform, glm::vec3(rectNDCPos, 0.0f));
|
||||
rectTransform = glm::scale(rectTransform, glm::vec3(rectNDCScale, 1.0f));
|
||||
|
||||
glUseProgram(shaderLine);
|
||||
|
||||
glBindVertexArray(self->rectVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(rectTransform));
|
||||
|
||||
glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(PREVIEW_NULL_TINT));
|
||||
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
mat4 rectModel = quad_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, frame.rotation, PERCENT_TO_UNIT(frame.scale));
|
||||
mat4 rectTransform = transform * (rootModel * rectModel);
|
||||
canvas_rect_draw(&self->canvas, shaderLine, rectTransform, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (self->isRecording && animation)
|
||||
s32& animationOverlayID = self->animationOverlayID;
|
||||
Anm2Animation* animationOverlay = map_find(self->anm2->animations, animationOverlayID);
|
||||
|
||||
if (animationOverlay)
|
||||
{
|
||||
if (recordFrameIndex == 0)
|
||||
Anm2Frame root;
|
||||
mat4 rootModel = mat4(1.0f);
|
||||
|
||||
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationOverlayID, ANM2_ROOT}, self->time);
|
||||
|
||||
if (self->settings->previewIsRootTransform)
|
||||
rootModel = quad_parent_model_get(root.position, vec2(0.0f), root.rotation, PERCENT_TO_UNIT(root.scale));
|
||||
|
||||
for (auto [i, id] : self->anm2->layerMap)
|
||||
{
|
||||
if
|
||||
(
|
||||
std::filesystem::exists(STRING_PREVIEW_FRAMES_DIRECTORY) &&
|
||||
std::filesystem::is_directory(STRING_PREVIEW_FRAMES_DIRECTORY))
|
||||
{
|
||||
for (const auto & entry : std::filesystem::directory_iterator(STRING_PREVIEW_FRAMES_DIRECTORY))
|
||||
std::filesystem::remove(entry);
|
||||
}
|
||||
else
|
||||
std::filesystem::create_directories(STRING_PREVIEW_FRAMES_DIRECTORY);
|
||||
self->isPlaying = true;
|
||||
}
|
||||
Anm2Frame frame;
|
||||
Anm2Item& layerAnimation = animation->layerAnimations[id];
|
||||
|
||||
if (isRecordThisFrame)
|
||||
{
|
||||
size_t frameSize = (self->recordSize.x * self->recordSize.y * 4);
|
||||
u8* frame = (u8*)calloc(frameSize, 1);
|
||||
std:: string path;
|
||||
if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
vec2 position =
|
||||
{
|
||||
self->settings->previewPanX - (PREVIEW_SIZE.x / 2.0f) + (self->recordSize.x / 2.0f),
|
||||
self->settings->previewPanY - (PREVIEW_SIZE.y / 2.0f) + (self->recordSize.y / 2.0f)
|
||||
};
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationOverlayID, ANM2_LAYER, id}, self->time);
|
||||
|
||||
path = std::format(STRING_PREVIEW_FRAMES_FORMAT, STRING_PREVIEW_FRAMES_DIRECTORY, recordFrameIndex);
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels
|
||||
(
|
||||
(s32)position.x,
|
||||
(s32)position.y,
|
||||
self->recordSize.x,
|
||||
self->recordSize.y,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
frame
|
||||
);
|
||||
Texture texture = self->resources->textures[self->anm2->layers[id].spritesheetID];
|
||||
|
||||
texture_from_data_write(path, frame, self->recordSize.x, self->recordSize.y);
|
||||
if (texture.isInvalid)
|
||||
continue;
|
||||
|
||||
free(frame);
|
||||
vec2 uvMin = frame.crop / vec2(texture.size);
|
||||
vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size);
|
||||
f32 vertices[] = UV_VERTICES(uvMin, uvMax);
|
||||
|
||||
isRecordThisFrame = false;
|
||||
recordFrameIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->time >= (f32)animation->frameNum - 1)
|
||||
{
|
||||
self->isRecording = false;
|
||||
self->isPlaying = false;
|
||||
recordFrameIndex = 0;
|
||||
recordFrameTimeNext = 0;
|
||||
self->time = 0.0f;
|
||||
}
|
||||
else if (self->time >= recordFrameTimeNext)
|
||||
{
|
||||
isRecordThisFrame = true;
|
||||
recordFrameTimeNext = self->time + (f32)self->anm2->fps / TICK_RATE;
|
||||
}
|
||||
mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, frame.rotation, PERCENT_TO_UNIT(frame.scale));
|
||||
mat4 layerTransform = transform * (rootModel * model);
|
||||
|
||||
vec4 tint = frame.tintRGBA;
|
||||
tint.a *= U8_TO_FLOAT(self->settings->previewOverlayTransparency);
|
||||
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, layerTransform, vertices, tint, frame.offsetRGB);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
canvas_unbind();
|
||||
}
|
||||
|
||||
void preview_free(Preview* self)
|
||||
{
|
||||
glDeleteTextures(1, &self->texture);
|
||||
glDeleteFramebuffers(1, &self->fbo);
|
||||
glDeleteRenderbuffers(1, &self->rbo);
|
||||
canvas_free(&self->canvas);
|
||||
}
|
@@ -6,6 +6,7 @@
|
||||
#include "canvas.h"
|
||||
|
||||
const vec2 PREVIEW_SIZE = {2000, 2000};
|
||||
const vec2 PREVIEW_CANVAS_SIZE = {2000, 2000};
|
||||
const vec2 PREVIEW_CENTER = {0, 0};
|
||||
|
||||
#define PREVIEW_ZOOM_MIN 1
|
||||
@@ -18,11 +19,12 @@ const vec2 PREVIEW_CENTER = {0, 0};
|
||||
|
||||
const vec2 PREVIEW_NULL_RECT_SIZE = {100, 100};
|
||||
const vec2 PREVIEW_POINT_SIZE = {2, 2};
|
||||
const vec2 PREVIEW_PIVOT_SIZE = {4, 4};
|
||||
const vec4 PREVIEW_ROOT_TINT = COLOR_GREEN;
|
||||
const vec4 PREVIEW_NULL_TINT = COLOR_BLUE;
|
||||
const vec4 PREVIEW_PIVOT_TINT = COLOR_RED;
|
||||
const vec2 PREVIEW_TARGET_SIZE = {16, 16};
|
||||
const vec4 PREVIEW_BORDER_COLOR = COLOR_RED;
|
||||
const vec4 PREVIEW_ROOT_COLOR = COLOR_GREEN;
|
||||
const vec4 PREVIEW_NULL_COLOR = COLOR_BLUE;
|
||||
const vec4 PREVIEW_NULL_SELECTED_COLOR = COLOR_RED;
|
||||
const vec4 PREVIEW_PIVOT_COLOR = COLOR_RED;
|
||||
|
||||
struct Preview
|
||||
{
|
||||
@@ -30,21 +32,10 @@ struct Preview
|
||||
Anm2Reference* reference = nullptr;
|
||||
Resources* resources = nullptr;
|
||||
Settings* settings = nullptr;
|
||||
GLuint axisVAO = ID_NONE;
|
||||
GLuint axisVBO = ID_NONE;
|
||||
GLuint fbo = ID_NONE;
|
||||
GLuint gridVAO = ID_NONE;
|
||||
GLuint gridVBO = ID_NONE;
|
||||
GLuint rbo = ID_NONE;
|
||||
GLuint texture = ID_NONE;
|
||||
GLuint rectVAO = ID_NONE;
|
||||
GLuint rectVBO = ID_NONE;
|
||||
GLuint textureEBO = ID_NONE;
|
||||
GLuint textureVAO = ID_NONE;
|
||||
GLuint textureVBO = ID_NONE;
|
||||
s32 animationOverlayID = ID_NONE;
|
||||
Canvas canvas;
|
||||
bool isPlaying = false;
|
||||
bool isRecording = false;
|
||||
vec2 recordSize{};
|
||||
f32 time{};
|
||||
};
|
||||
|
||||
|
105
src/settings.cpp
105
src/settings.cpp
@@ -2,34 +2,59 @@
|
||||
|
||||
static void _settings_setting_load(Settings* self, const std::string& line)
|
||||
{
|
||||
for (s32 i = 0; i < SETTINGS_COUNT; i++)
|
||||
for (s32 i = 0; i < SETTINGS_COUNT; i++)
|
||||
{
|
||||
const std::string& key = SETTINGS_ENTRIES[i].key;
|
||||
size_t keyLength = key.length();
|
||||
const auto& entry = SETTINGS_ENTRIES[i];
|
||||
const std::string& key = entry.key;
|
||||
void* target = (u8*)self + entry.offset;
|
||||
|
||||
if (line.compare(0, keyLength, key) == 0)
|
||||
auto match_key = [&](const std::string& full) -> const char*
|
||||
{
|
||||
const char* value = line.c_str() + keyLength;
|
||||
void* target = (u8*)self + SETTINGS_ENTRIES[i].offset;
|
||||
return (line.starts_with(full) && line[full.size()] == '=') ? line.c_str() + full.size() + 1 : nullptr;
|
||||
};
|
||||
|
||||
switch (SETTINGS_ENTRIES[i].type)
|
||||
auto* value = match_key(key);
|
||||
|
||||
if (value)
|
||||
{
|
||||
switch (entry.type)
|
||||
{
|
||||
case SETTINGS_TYPE_INT:
|
||||
*(s32*)target = std::atoi(value);
|
||||
break;
|
||||
case SETTINGS_TYPE_BOOL:
|
||||
*(s32*)target = string_to_bool(std::string(value));
|
||||
break;
|
||||
case SETTINGS_TYPE_FLOAT:
|
||||
*(f32*)target = std::atof(value);
|
||||
break;
|
||||
case SETTINGS_TYPE_STRING:
|
||||
*(std::string*)target = std::string(value);
|
||||
break;
|
||||
default:
|
||||
case TYPE_INT:
|
||||
*(s32*)target = std::atoi(value);
|
||||
return;
|
||||
case TYPE_BOOL:
|
||||
*(bool*)target = string_to_bool(value);
|
||||
return;
|
||||
case TYPE_FLOAT:
|
||||
*(f32*)target = std::atof(value);
|
||||
return;
|
||||
case TYPE_STRING:
|
||||
*(std::string*)target = value;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.type == TYPE_VEC2)
|
||||
{
|
||||
vec2* v = (vec2*)target;
|
||||
if ((value = match_key(key + "X"))) { v->x = std::atof(value); return; }
|
||||
if ((value = match_key(key + "Y"))) { v->y = std::atof(value); return; }
|
||||
}
|
||||
else if (entry.type == TYPE_IVEC2)
|
||||
{
|
||||
ivec2* v = (ivec2*)target;
|
||||
if ((value = match_key(key + "X"))) { v->x = std::atoi(value); return; }
|
||||
if ((value = match_key(key + "Y"))) { v->y = std::atoi(value); return; }
|
||||
}
|
||||
else if (entry.type == TYPE_VEC4)
|
||||
{
|
||||
vec4* v = (vec4*)target;
|
||||
if ((value = match_key(key + "R"))) { v->x = std::atof(value); return; }
|
||||
if ((value = match_key(key + "G"))) { v->y = std::atof(value); return; }
|
||||
if ((value = match_key(key + "B"))) { v->z = std::atof(value); return; }
|
||||
if ((value = match_key(key + "A"))) { v->w = std::atof(value); return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,23 +66,48 @@ static void _settings_setting_write(Settings* self, std::ostream& out, SettingsE
|
||||
|
||||
switch (entry.type)
|
||||
{
|
||||
case SETTINGS_TYPE_INT:
|
||||
case TYPE_INT:
|
||||
value = std::format("{}", *(s32*)(selfPointer + entry.offset));
|
||||
out << entry.key << "=" << value << "\n";
|
||||
break;
|
||||
case SETTINGS_TYPE_BOOL:
|
||||
case TYPE_BOOL:
|
||||
value = std::format("{}", *(bool*)(selfPointer + entry.offset));
|
||||
out << entry.key << "=" << value << "\n";
|
||||
break;
|
||||
case SETTINGS_TYPE_FLOAT:
|
||||
case TYPE_FLOAT:
|
||||
value = std::format("{:.3f}", *(f32*)(selfPointer + entry.offset));
|
||||
out << entry.key << "=" << value << "\n";
|
||||
break;
|
||||
case SETTINGS_TYPE_STRING:
|
||||
case TYPE_STRING:
|
||||
value = *(std::string*)(selfPointer + entry.offset);
|
||||
out << entry.key << "=" << value << "\n";
|
||||
break;
|
||||
case TYPE_IVEC2:
|
||||
{
|
||||
ivec2* data = (ivec2*)(selfPointer + entry.offset);
|
||||
out << entry.key << "X=" << data->x << "\n";
|
||||
out << entry.key << "Y=" << data->y << "\n";
|
||||
break;
|
||||
}
|
||||
case TYPE_VEC2:
|
||||
{
|
||||
vec2* data = (vec2*)(selfPointer + entry.offset);
|
||||
out << entry.key << "X=" << std::format(SETTINGS_FLOAT_FORMAT, data->x) << "\n";
|
||||
out << entry.key << "Y=" << std::format(SETTINGS_FLOAT_FORMAT, data->y) << "\n";
|
||||
break;
|
||||
}
|
||||
case TYPE_VEC4:
|
||||
{
|
||||
vec4* data = (vec4*)(selfPointer + entry.offset);
|
||||
out << entry.key << "R=" << std::format(SETTINGS_FLOAT_FORMAT, data->r) << "\n";
|
||||
out << entry.key << "G=" << std::format(SETTINGS_FLOAT_FORMAT, data->g) << "\n";
|
||||
out << entry.key << "B=" << std::format(SETTINGS_FLOAT_FORMAT, data->b) << "\n";
|
||||
out << entry.key << "A=" << std::format(SETTINGS_FLOAT_FORMAT, data->a) << "\n";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
out << entry.key << value << "\n";
|
||||
}
|
||||
|
||||
void settings_save(Settings* self)
|
||||
@@ -75,6 +125,7 @@ void settings_save(Settings* self)
|
||||
input.close();
|
||||
|
||||
std::ofstream output(SETTINGS_PATH);
|
||||
|
||||
if (!output)
|
||||
{
|
||||
log_error(std::format(SETTINGS_INIT_ERROR, SETTINGS_PATH));
|
||||
|
145
src/settings.h
145
src/settings.h
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "COMMON.h"
|
||||
#include "tool.h"
|
||||
|
||||
#define SETTINGS_BUFFER 0xFFFF
|
||||
#define SETTINGS_BUFFER_ITEM 0xFF
|
||||
@@ -8,124 +8,73 @@
|
||||
#define SETTINGS_SECTION_IMGUI "# Dear ImGui"
|
||||
#define SETTINGS_INIT_ERROR "Failed to read settings file! ({})"
|
||||
#define SETTINGS_PATH "settings.ini"
|
||||
|
||||
enum SettingsValueType
|
||||
{
|
||||
SETTINGS_TYPE_INT,
|
||||
SETTINGS_TYPE_FLOAT,
|
||||
SETTINGS_TYPE_BOOL,
|
||||
SETTINGS_TYPE_STRING
|
||||
};
|
||||
#define SETTINGS_FLOAT_FORMAT "{:.3f}"
|
||||
|
||||
struct SettingsEntry
|
||||
{
|
||||
std::string key;
|
||||
SettingsValueType type;
|
||||
DataType type;
|
||||
s32 offset;
|
||||
};
|
||||
|
||||
struct Settings
|
||||
{
|
||||
s32 windowW = 1920;
|
||||
s32 windowH = 1080;
|
||||
ivec2 windowSize = {1080, 720};
|
||||
bool playbackIsLoop = true;
|
||||
bool previewIsAxis = true;
|
||||
bool previewIsGrid = true;
|
||||
bool previewIsRootTransform = false;
|
||||
bool previewIsShowPivot = false;
|
||||
f32 previewPanX = 0.0f;
|
||||
f32 previewPanY = 0.0f;
|
||||
f32 previewZoom = 200.0f;
|
||||
s32 previewGridSizeX = 32;
|
||||
s32 previewGridSizeY = 32;
|
||||
s32 previewGridOffsetX = 0;
|
||||
s32 previewGridOffsetY = 0;
|
||||
f32 previewGridColorR = 1.0f;
|
||||
f32 previewGridColorG = 1.0f;
|
||||
f32 previewGridColorB = 1.0f;
|
||||
f32 previewGridColorA = 0.125f;
|
||||
f32 previewAxisColorR = 1.0f;
|
||||
f32 previewAxisColorG = 1.0f;
|
||||
f32 previewAxisColorB = 1.0f;
|
||||
f32 previewAxisColorA = 0.5f;
|
||||
f32 previewBackgroundColorR = 0.113f;
|
||||
f32 previewBackgroundColorG = 0.184f;
|
||||
f32 previewBackgroundColorB = 0.286f;
|
||||
f32 previewBackgroundColorA = 1.0f;
|
||||
bool previewIsBorder = false;
|
||||
f32 previewOverlayTransparency = 255.0f;
|
||||
f32 previewZoom = 200.0;
|
||||
vec2 previewPan = {0.0, 0.0};
|
||||
ivec2 previewGridSize = {32, 32};
|
||||
ivec2 previewGridOffset{};
|
||||
vec4 previewGridColor = {1.0, 1.0, 1.0, 0.125};
|
||||
vec4 previewAxisColor = {1.0, 1.0, 1.0, 0.125};
|
||||
vec4 previewBackgroundColor = {0.113, 0.184, 0.286, 1.0};
|
||||
bool editorIsGrid = true;
|
||||
bool editorIsGridSnap = true;
|
||||
bool editorIsBorder = true;
|
||||
f32 editorPanX = 0.0f;
|
||||
f32 editorPanY = 0.0f;
|
||||
f32 editorZoom = 200.0f;
|
||||
s32 editorGridSizeX = 32;
|
||||
s32 editorGridSizeY = 32;
|
||||
s32 editorGridOffsetX = 32;
|
||||
s32 editorGridOffsetY = 32;
|
||||
f32 editorGridColorR = 1.0f;
|
||||
f32 editorGridColorG = 1.0f;
|
||||
f32 editorGridColorB = 1.0f;
|
||||
f32 editorGridColorA = 0.125f;
|
||||
f32 editorBackgroundColorR = 0.113f;
|
||||
f32 editorBackgroundColorG = 0.184f;
|
||||
f32 editorBackgroundColorB = 0.286f;
|
||||
f32 editorBackgroundColorA = 1.0f;
|
||||
f32 toolColorR = 1.0f;
|
||||
f32 toolColorG = 1.0f;
|
||||
f32 toolColorB = 1.0f;
|
||||
f32 toolColorA = 1.0f;
|
||||
f32 editorZoom = 200.0;
|
||||
vec2 editorPan = {0.0, 0.0};
|
||||
ivec2 editorGridSize = {32, 32};
|
||||
ivec2 editorGridOffset = {32, 32};
|
||||
vec4 editorGridColor = {1.0, 1.0, 1.0, 0.125};
|
||||
vec4 editorBackgroundColor = {0.113, 0.184, 0.286, 1.0};
|
||||
ToolType tool = TOOL_PAN;
|
||||
vec4 toolColor = {1.0, 1.0, 1.0, 1.0};
|
||||
};
|
||||
|
||||
const SettingsEntry SETTINGS_ENTRIES[] =
|
||||
{
|
||||
{"windowW=", SETTINGS_TYPE_INT, offsetof(Settings, windowW)},
|
||||
{"windowH=", SETTINGS_TYPE_INT, offsetof(Settings, windowH)},
|
||||
{"playbackIsLoop=", SETTINGS_TYPE_BOOL, offsetof(Settings, playbackIsLoop)},
|
||||
{"previewIsAxis=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsAxis)},
|
||||
{"previewIsGrid=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsGrid)},
|
||||
{"previewIsRootTransform=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsRootTransform)},
|
||||
{"previewIsShowPivot=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsShowPivot)},
|
||||
{"previewPanX=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanX)},
|
||||
{"previewPanY=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanY)},
|
||||
{"previewZoom=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewZoom)},
|
||||
{"previewGridSizeX=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeX)},
|
||||
{"previewGridSizeY=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeY)},
|
||||
{"previewGridOffsetX=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetX)},
|
||||
{"previewGridOffsetY=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetY)},
|
||||
{"previewGridColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorR)},
|
||||
{"previewGridColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorG)},
|
||||
{"previewGridColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorB)},
|
||||
{"previewGridColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorA)},
|
||||
{"previewAxisColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorR)},
|
||||
{"previewAxisColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorG)},
|
||||
{"previewAxisColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorB)},
|
||||
{"previewAxisColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorA)},
|
||||
{"previewBackgroundColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorR)},
|
||||
{"previewBackgroundColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorG)},
|
||||
{"previewBackgroundColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorB)},
|
||||
{"previewBackgroundColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorA)},
|
||||
{"editorIsGrid=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGrid)},
|
||||
{"editorIsGridSnap=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGridSnap)},
|
||||
{"editorIsBorder=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsBorder)},
|
||||
{"editorPanX=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanX)},
|
||||
{"editorPanY=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanY)},
|
||||
{"editorZoom=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorZoom)},
|
||||
{"editorGridSizeX=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeX)},
|
||||
{"editorGridSizeY=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeY)},
|
||||
{"editorGridOffsetX=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetX)},
|
||||
{"editorGridOffsetY=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetY)},
|
||||
{"editorGridColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorR)},
|
||||
{"editorGridColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorG)},
|
||||
{"editorGridColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorB)},
|
||||
{"editorGridColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorA)},
|
||||
{"editorBackgroundColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorR)},
|
||||
{"editorBackgroundColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorG)},
|
||||
{"editorBackgroundColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorB)},
|
||||
{"editorBackgroundColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorA)},
|
||||
{"toolColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, toolColorR)},
|
||||
{"toolColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, toolColorG)},
|
||||
{"toolColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, toolColorB)},
|
||||
{"toolColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, toolColorA)}
|
||||
{"window", TYPE_IVEC2, offsetof(Settings, windowSize)},
|
||||
{"playbackIsLoop", TYPE_BOOL, offsetof(Settings, playbackIsLoop)},
|
||||
{"previewIsAxis", TYPE_BOOL, offsetof(Settings, previewIsAxis)},
|
||||
{"previewIsGrid", TYPE_BOOL, offsetof(Settings, previewIsGrid)},
|
||||
{"previewIsRootTransform", TYPE_BOOL, offsetof(Settings, previewIsRootTransform)},
|
||||
{"previewIsShowPivot", TYPE_BOOL, offsetof(Settings, previewIsShowPivot)},
|
||||
{"previewIsBorder", TYPE_BOOL, offsetof(Settings, previewIsBorder)},
|
||||
{"previewOverlayTransparency", TYPE_FLOAT, offsetof(Settings, previewOverlayTransparency)},
|
||||
{"previewZoom", TYPE_FLOAT, offsetof(Settings, previewZoom)},
|
||||
{"previewPan", TYPE_VEC2, offsetof(Settings, previewPan)},
|
||||
{"previewGridSize", TYPE_IVEC2, offsetof(Settings, previewGridSize)},
|
||||
{"previewGridOffset", TYPE_IVEC2, offsetof(Settings, previewGridOffset)},
|
||||
{"previewGridColor", TYPE_VEC4, offsetof(Settings, previewGridColor)},
|
||||
{"previewAxisColor", TYPE_VEC4, offsetof(Settings, previewAxisColor)},
|
||||
{"previewBackgroundColor", TYPE_VEC4, offsetof(Settings, previewBackgroundColor)},
|
||||
{"editorIsGrid", TYPE_BOOL, offsetof(Settings, editorIsGrid)},
|
||||
{"editorIsGridSnap", TYPE_BOOL, offsetof(Settings, editorIsGridSnap)},
|
||||
{"editorIsBorder", TYPE_BOOL, offsetof(Settings, editorIsBorder)},
|
||||
{"editorZoom", TYPE_FLOAT, offsetof(Settings, editorZoom)},
|
||||
{"editorPan", TYPE_VEC2, offsetof(Settings, editorPan)},
|
||||
{"editorGridSize", TYPE_IVEC2, offsetof(Settings, editorGridSize)},
|
||||
{"editorGridOffset", TYPE_IVEC2, offsetof(Settings, editorGridOffset)},
|
||||
{"editorGridColor", TYPE_VEC4, offsetof(Settings, editorGridColor)},
|
||||
{"editorBackgroundColor", TYPE_VEC4, offsetof(Settings, editorBackgroundColor)},
|
||||
{"tool", TYPE_INT, offsetof(Settings, tool)},
|
||||
{"toolColor", TYPE_VEC4, offsetof(Settings, toolColor)},
|
||||
};
|
||||
constexpr s32 SETTINGS_COUNT = (s32)std::size(SETTINGS_ENTRIES);
|
||||
|
||||
|
@@ -2,20 +2,18 @@
|
||||
|
||||
static bool _shader_compile(GLuint* self, const std::string& text)
|
||||
{
|
||||
std::string compileLog;
|
||||
s32 isCompile;
|
||||
|
||||
const GLchar* source = text.c_str();
|
||||
|
||||
glShaderSource(*self, 1, &source, nullptr);
|
||||
|
||||
glCompileShader(*self);
|
||||
glGetShaderiv(*self, GL_COMPILE_STATUS, &isCompile);
|
||||
|
||||
if (!isCompile)
|
||||
{
|
||||
glGetShaderInfoLog(*self, SHADER_INFO_LOG_MAX, nullptr, &compileLog[0]);
|
||||
log_error(std::format(SHADER_INIT_ERROR, *self, compileLog));
|
||||
std::string compileLog(SHADER_INFO_LOG_MAX, '\0');
|
||||
glGetShaderInfoLog(*self, SHADER_INFO_LOG_MAX, nullptr, compileLog.data());
|
||||
log_error(std::format(SHADER_INIT_ERROR, *self, compileLog.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,7 @@ static void _snapshot_set(Snapshots* self, const Snapshot& snapshot)
|
||||
*self->anm2 = snapshot.anm2;
|
||||
*self->reference = snapshot.reference;
|
||||
self->preview->time = snapshot.time;
|
||||
self->action = snapshot.action;
|
||||
}
|
||||
|
||||
void snapshots_init(Snapshots* self, Anm2* anm2, Anm2Reference* reference, Preview* preview)
|
||||
@@ -44,7 +45,7 @@ void snapshots_undo(Snapshots* self)
|
||||
Snapshot snapshot;
|
||||
if (_snapshot_stack_pop(&self->undoStack, &snapshot))
|
||||
{
|
||||
Snapshot current = {*self->anm2, *self->reference, self->preview->time};
|
||||
Snapshot current = {*self->anm2, *self->reference, self->preview->time, self->action};
|
||||
_snapshot_stack_push(&self->redoStack, ¤t);
|
||||
_snapshot_set(self, snapshot);
|
||||
}
|
||||
@@ -55,7 +56,7 @@ void snapshots_redo(Snapshots* self)
|
||||
Snapshot snapshot;
|
||||
if (_snapshot_stack_pop(&self->redoStack, &snapshot))
|
||||
{
|
||||
Snapshot current = {*self->anm2, *self->reference, self->preview->time};
|
||||
Snapshot current = {*self->anm2, *self->reference, self->preview->time, self->action};
|
||||
_snapshot_stack_push(&self->undoStack, ¤t);
|
||||
_snapshot_set(self, snapshot);
|
||||
}
|
||||
|
@@ -3,13 +3,15 @@
|
||||
#include "anm2.h"
|
||||
#include "preview.h"
|
||||
|
||||
#define SNAPSHOT_STACK_MAX 100
|
||||
#define SNAPSHOT_STACK_MAX 1000
|
||||
#define SNAPSHOT_ACTION "Action"
|
||||
|
||||
struct Snapshot
|
||||
{
|
||||
Anm2 anm2;
|
||||
Anm2Reference reference;
|
||||
f32 time = 0.0f;
|
||||
std::string action = SNAPSHOT_ACTION;
|
||||
};
|
||||
|
||||
struct SnapshotStack
|
||||
@@ -23,6 +25,7 @@ struct Snapshots
|
||||
Anm2* anm2 = nullptr;
|
||||
Preview* preview = nullptr;
|
||||
Anm2Reference* reference = nullptr;
|
||||
std::string action = SNAPSHOT_ACTION;
|
||||
SnapshotStack undoStack;
|
||||
SnapshotStack redoStack;
|
||||
};
|
||||
|
@@ -2,14 +2,18 @@
|
||||
|
||||
static void _tick(State* self)
|
||||
{
|
||||
SDL_GetWindowSize(self->window, &self->settings.windowW, &self->settings.windowH);
|
||||
|
||||
editor_tick(&self->editor);
|
||||
preview_tick(&self->preview);
|
||||
dialog_tick(&self->dialog);
|
||||
imgui_tick(&self->imgui);
|
||||
}
|
||||
|
||||
if (self->imgui.isQuit) self->isRunning = false;
|
||||
static void _update(State* self)
|
||||
{
|
||||
SDL_GetWindowSize(self->window, &self->settings.windowSize.x, &self->settings.windowSize.y);
|
||||
|
||||
imgui_update(&self->imgui);
|
||||
dialog_update(&self->dialog);
|
||||
|
||||
if (self->imgui.isQuit)
|
||||
self->isRunning = false;
|
||||
}
|
||||
|
||||
static void _draw(State* self)
|
||||
@@ -35,11 +39,37 @@ void init(State* self)
|
||||
|
||||
log_info(STATE_SDL_INIT_INFO);
|
||||
|
||||
// Todo, when sdl3 mixer is released officially
|
||||
/*
|
||||
if ((Mix_Init(STATE_MIX_FLAGS) & mixFlags) != mixFlags)
|
||||
log_warning(std::format(STATE_MIX_INIT_WARNING, Mix_GetError()));
|
||||
|
||||
if
|
||||
(
|
||||
Mix_OpenAudioDevice
|
||||
(
|
||||
STATE_MIX_SAMPLE_RATE,
|
||||
STATE_MIX_FORMAT,
|
||||
STATE_MIX_CHANNELS,
|
||||
STATE_CHUNK_SIZE,
|
||||
STATE_MIX_DEVICE,
|
||||
STATE_MIX_ALLOWED_CHANGES
|
||||
)
|
||||
< 0
|
||||
)
|
||||
{
|
||||
log_warning(std::format(STATE_MIX_INIT_WARNING, Mix_GetError()));
|
||||
Mix_Quit();
|
||||
}
|
||||
else
|
||||
log_info(STATE_MIX_INIT_INFO);
|
||||
*/
|
||||
|
||||
SDL_CreateWindowAndRenderer
|
||||
(
|
||||
WINDOW_TITLE,
|
||||
self->settings.windowW,
|
||||
self->settings.windowH,
|
||||
self->settings.windowSize.x,
|
||||
self->settings.windowSize.y,
|
||||
WINDOW_FLAGS,
|
||||
&self->window,
|
||||
&self->renderer
|
||||
@@ -63,9 +93,11 @@ void init(State* self)
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glLineWidth(STATE_GL_LINE_WIDTH);
|
||||
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
|
||||
resources_init(&self->resources);
|
||||
clipboard_init(&self->clipboard, &self->anm2);
|
||||
dialog_init(&self->dialog, &self->anm2, &self->reference, &self->resources, self->window);
|
||||
@@ -98,6 +130,7 @@ void init(State* self)
|
||||
anm2_new(&self->anm2);
|
||||
}
|
||||
|
||||
|
||||
void loop(State* self)
|
||||
{
|
||||
self->tick = SDL_GetTicks();
|
||||
@@ -112,22 +145,27 @@ void loop(State* self)
|
||||
_tick(self);
|
||||
|
||||
self->lastTick = self->tick;
|
||||
|
||||
}
|
||||
|
||||
_update(self);
|
||||
_draw(self);
|
||||
}
|
||||
|
||||
void quit(State* self)
|
||||
{
|
||||
imgui_free();
|
||||
settings_save(&self->settings);
|
||||
preview_free(&self->preview);
|
||||
editor_free(&self->editor);
|
||||
resources_free(&self->resources);
|
||||
|
||||
/*
|
||||
Mix_CloseAudio();
|
||||
Mix_Quit();
|
||||
*/
|
||||
|
||||
SDL_GL_DestroyContext(self->glContext);
|
||||
SDL_Quit();
|
||||
|
||||
settings_save(&self->settings);
|
||||
log_info(STATE_QUIT_INFO);
|
||||
}
|
19
src/state.h
19
src/state.h
@@ -5,11 +5,22 @@
|
||||
#define STATE_INIT_INFO "Initializing..."
|
||||
#define STATE_SDL_INIT_ERROR "Failed to initialize SDL! {}"
|
||||
#define STATE_SDL_INIT_INFO "Initialized SDL"
|
||||
#define STATE_MIX_INIT_WARNING "Unable to initialize SDL_mixer! {}"
|
||||
#define STATE_MIX_AUDIO_DEVICE_INIT_WARNING "Unable to initialize audio device! {}"
|
||||
#define STATE_MIX_INIT_INFO "Initialized SDL_mixer"
|
||||
#define STATE_GL_CONTEXT_INIT_ERROR "Failed to initialize OpenGL context! {}"
|
||||
#define STATE_GL_CONTEXT_INIT_INFO "Initialized OpenGL context (OpenGL {})"
|
||||
#define STATE_QUIT_INFO "Exiting..."
|
||||
#define STATE_GL_LINE_WIDTH 2.0f
|
||||
|
||||
#define STATE_MIX_FLAGS (MIX_INIT_MP3 | MIX_INIT_OGG | MIX_INIT_WAV)
|
||||
#define STATE_MIX_SAMPLE_RATE 44100
|
||||
#define STATE_MIX_FORMAT MIX_DEFAULT_FORMAT
|
||||
#define STATE_MIX_CHANNELS 2
|
||||
#define STATE_MIX_CHUNK_SIZE 1024
|
||||
#define STATE_MIX_DEVICE NULL
|
||||
#define STATE_MIX_ALLOWED_CHANGES SDL_AUDIO_ALLOW_FORMAT_CHANGE
|
||||
|
||||
struct State
|
||||
{
|
||||
SDL_Window* window;
|
||||
@@ -25,11 +36,13 @@ struct State
|
||||
Settings settings;
|
||||
Snapshots snapshots;
|
||||
Clipboard clipboard;
|
||||
bool isRunning = true;
|
||||
std::string argument{};
|
||||
u64 lastTick = 0;
|
||||
u64 tick = 0;
|
||||
std::string lastAction{};
|
||||
u64 lastTick{};
|
||||
u64 tick{};
|
||||
bool isRunning = true;
|
||||
|
||||
bool is_last_action() const { return !lastAction.empty(); }
|
||||
bool is_argument() const { return !argument.empty(); }
|
||||
};
|
||||
|
||||
|
@@ -8,6 +8,18 @@
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
|
||||
static std::vector<u8> _texture_download(Texture* self)
|
||||
{
|
||||
std::vector<u8> pixels(self->size.x * self->size.y * TEXTURE_CHANNELS);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, self->id);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
return pixels;
|
||||
}
|
||||
|
||||
void texture_gl_set(Texture* self, void* data)
|
||||
{
|
||||
glGenTextures(1, &self->id);
|
||||
@@ -48,13 +60,37 @@ bool texture_from_data_init(Texture* self, const u8* data, u32 length)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool texture_from_data_write(const std::string& path, const u8* data, s32 width, s32 height)
|
||||
bool texture_from_data_write(const std::string& path, const u8* data, ivec2 size)
|
||||
{
|
||||
return (bool)stbi_write_png(path.c_str(), width, height, TEXTURE_CHANNELS, data, width * TEXTURE_CHANNELS);
|
||||
log_info(std::format(TEXTURE_SAVE_INFO, path));
|
||||
return (bool)stbi_write_png(path.c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS);
|
||||
}
|
||||
|
||||
bool texture_from_gl_write(Texture* self, const std::string& path)
|
||||
{
|
||||
return texture_from_data_write(path, _texture_download(self).data(), self->size);
|
||||
}
|
||||
|
||||
void texture_free(Texture* self)
|
||||
{
|
||||
glDeleteTextures(1, &self->id);
|
||||
*self = Texture{};
|
||||
}
|
||||
}
|
||||
|
||||
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color)
|
||||
{
|
||||
if
|
||||
(
|
||||
position.x < 0 || position.y < 0 ||
|
||||
position.x >= self->size.x || position.y >= self->size.y
|
||||
)
|
||||
return false;
|
||||
|
||||
uint8_t rgba8[4] = {FLOAT_TO_U8(color.r), FLOAT_TO_U8(color.g), FLOAT_TO_U8(color.b), FLOAT_TO_U8(color.a)};
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, self->id);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0,position.x, position.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, rgba8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#define TEXTURE_CHANNELS 4
|
||||
#define TEXTURE_INIT_INFO "Initialized texture from file: {}"
|
||||
#define TEXTURE_INIT_ERROR "Failed to initialize texture from file: {}"
|
||||
#define TEXTURE_SAVE_INFO "Saved texture to: {}"
|
||||
|
||||
struct Texture
|
||||
{
|
||||
@@ -18,4 +19,7 @@ void texture_gl_set(Texture* self, void* data);
|
||||
bool texture_from_path_init(Texture* self, const std::string& path);
|
||||
bool texture_from_data_init(Texture* self, const u8* data, u32 length);
|
||||
void texture_free(Texture* self);
|
||||
bool texture_from_data_write(const std::string& path, const u8* data, s32 width, s32 height);
|
||||
std::vector<u8> texture_download(Texture* self);
|
||||
bool texture_from_data_write(const std::string& path, const u8* data, ivec2 size);
|
||||
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
||||
bool texture_from_gl_write(Texture* self, const std::string& path);
|
52
src/tool.h
Normal file
52
src/tool.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "COMMON.h"
|
||||
|
||||
#define TOOL_STEP 1
|
||||
#define TOOL_STEP_MOD 10
|
||||
|
||||
enum ToolType
|
||||
{
|
||||
TOOL_PAN,
|
||||
TOOL_MOVE,
|
||||
TOOL_ROTATE,
|
||||
TOOL_SCALE,
|
||||
TOOL_CROP,
|
||||
TOOL_DRAW,
|
||||
TOOL_ERASE,
|
||||
TOOL_COLOR_PICKER,
|
||||
TOOL_UNDO,
|
||||
TOOL_REDO,
|
||||
TOOL_COLOR,
|
||||
TOOL_COUNT,
|
||||
};
|
||||
|
||||
const SDL_SystemCursor MOUSE_CURSOR_DEFAULT = SDL_SYSTEM_CURSOR_DEFAULT;
|
||||
const SDL_SystemCursor TOOL_MOUSE_CURSORS[TOOL_COUNT] =
|
||||
{
|
||||
SDL_SYSTEM_CURSOR_POINTER,
|
||||
SDL_SYSTEM_CURSOR_MOVE,
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR,
|
||||
SDL_SYSTEM_CURSOR_NE_RESIZE,
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR,
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR,
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR,
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR,
|
||||
SDL_SYSTEM_CURSOR_DEFAULT,
|
||||
SDL_SYSTEM_CURSOR_DEFAULT
|
||||
};
|
||||
|
||||
const bool TOOL_MOUSE_CURSOR_IS_CONSTANT[TOOL_COUNT] =
|
||||
{
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
};
|
@@ -4,8 +4,7 @@
|
||||
|
||||
#define WINDOW_TITLE "Anm2Ed"
|
||||
#define WINDOW_TITLE_FORMAT "Anm2Ed ({})"
|
||||
#define WINDOW_WIDTH 1920
|
||||
#define WINDOW_HEIGHT 1080
|
||||
#define WINDOW_FLAGS SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL
|
||||
|
||||
void window_title_from_path_set(SDL_Window* self, const std::string& path);
|
||||
void window_title_from_path_set(SDL_Window* self, const std::string& path);
|
||||
bool window_color_from_position_get(SDL_Window* self, vec2 position, vec4* color);
|
Reference in New Issue
Block a user