The Update(TM), Part 2

This commit is contained in:
2025-08-09 00:32:14 -04:00
parent fe8bdae9a8
commit b9c9105621
29 changed files with 2656 additions and 1987 deletions

View File

@@ -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}")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -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
};

View File

@@ -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}
};

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}
*/

View File

@@ -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
);

View File

@@ -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;
}

View File

@@ -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>;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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{};
};

View File

@@ -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));

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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, &current);
_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, &current);
_snapshot_set(self, snapshot);
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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(); }
};

View File

@@ -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;
}

View File

@@ -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
View 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
};

View File

@@ -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);