code:
/* libpng 1.6.34 STANDARD API DEFINITION */

/* pnglibconf.h - library build configuration */

/* Libpng version 1.6.34 - September 29, 2017 */

/* Copyright (c) 1998-2017 Glenn Randers-Pehrson */

/* This code is released under the libpng license. */
/* For conditions of distribution and use, see the disclaimer */
/* and license in png.h */

/* pnglibconf.h */
/* Machine generated file: DO NOT EDIT */
/* Derived from: scripts/pnglibconf.dfa */
#ifndef PNGLCONF_H
#define PNGLCONF_H
/* options */
#define PNG_16BIT_SUPPORTED
#define PNG_ALIGNED_MEMORY_SUPPORTED
/*#undef PNG_ARM_NEON_API_SUPPORTED*/
/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/
#define PNG_BENIGN_ERRORS_SUPPORTED
#define PNG_BENIGN_READ_ERRORS_SUPPORTED
/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/
#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_COLORSPACE_SUPPORTED
#define PNG_CONSOLE_IO_SUPPORTED
#define PNG_CONVERT_tIME_SUPPORTED
#define PNG_EASY_ACCESS_SUPPORTED
/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
#define PNG_ERROR_TEXT_SUPPORTED
#define PNG_FIXED_POINT_SUPPORTED
#define PNG_FLOATING_ARITHMETIC_SUPPORTED
#define PNG_FLOATING_POINT_SUPPORTED
#define PNG_FORMAT_AFIRST_SUPPORTED
#define PNG_FORMAT_BGR_SUPPORTED
#define PNG_GAMMA_SUPPORTED
#define PNG_GET_PALETTE_MAX_SUPPORTED
#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
#define PNG_MNG_FEATURES_SUPPORTED
#define PNG_POINTER_INDEXING_SUPPORTED
#define PNG_PROGRESSIVE_READ_SUPPORTED
#define PNG_READ_16BIT_SUPPORTED
#define PNG_READ_ALPHA_MODE_SUPPORTED
#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_READ_BACKGROUND_SUPPORTED
#define PNG_READ_BGR_SUPPORTED
#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
#define PNG_READ_EXPAND_16_SUPPORTED
#define PNG_READ_EXPAND_SUPPORTED
#define PNG_READ_FILLER_SUPPORTED
#define PNG_READ_GAMMA_SUPPORTED
#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
#define PNG_READ_GRAY_TO_RGB_SUPPORTED
#define PNG_READ_INTERLACING_SUPPORTED
#define PNG_READ_INT_FUNCTIONS_SUPPORTED
#define PNG_READ_INVERT_ALPHA_SUPPORTED
#define PNG_READ_INVERT_SUPPORTED
#define PNG_READ_OPT_PLTE_SUPPORTED
#define PNG_READ_PACKSWAP_SUPPORTED
#define PNG_READ_PACK_SUPPORTED
#define PNG_READ_QUANTIZE_SUPPORTED
#define PNG_READ_RGB_TO_GRAY_SUPPORTED
#define PNG_READ_SCALE_16_TO_8_SUPPORTED
#define PNG_READ_SHIFT_SUPPORTED
#define PNG_READ_STRIP_16_TO_8_SUPPORTED
#define PNG_READ_STRIP_ALPHA_SUPPORTED
#define PNG_READ_SUPPORTED
#define PNG_READ_SWAP_ALPHA_SUPPORTED
#define PNG_READ_SWAP_SUPPORTED
#define PNG_READ_TEXT_SUPPORTED
#define PNG_READ_TRANSFORMS_SUPPORTED
#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_READ_USER_CHUNKS_SUPPORTED
#define PNG_READ_USER_TRANSFORM_SUPPORTED
#define PNG_READ_bKGD_SUPPORTED
#define PNG_READ_cHRM_SUPPORTED
#define PNG_READ_eXIf_SUPPORTED
#define PNG_READ_gAMA_SUPPORTED
#define PNG_READ_hIST_SUPPORTED
#define PNG_READ_iCCP_SUPPORTED
#define PNG_READ_iTXt_SUPPORTED
#define PNG_READ_oFFs_SUPPORTED
#define PNG_READ_pCAL_SUPPORTED
#define PNG_READ_pHYs_SUPPORTED
#define PNG_READ_sBIT_SUPPORTED
#define PNG_READ_sCAL_SUPPORTED
#define PNG_READ_sPLT_SUPPORTED
#define PNG_READ_sRGB_SUPPORTED
#define PNG_READ_tEXt_SUPPORTED
#define PNG_READ_tIME_SUPPORTED
#define PNG_READ_tRNS_SUPPORTED
#define PNG_READ_zTXt_SUPPORTED
/*#undef PNG_SAVE_INT_32_SUPPORTED*/
#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_SEQUENTIAL_READ_SUPPORTED
#define PNG_SETJMP_SUPPORTED
#define PNG_SET_OPTION_SUPPORTED
#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_SET_USER_LIMITS_SUPPORTED
/*#undef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_READ_BGR_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_READ_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED*/
/*#undef PNG_SIMPLIFIED_WRITE_SUPPORTED*/
/*#undef PNG_STDIO_SUPPORTED*/
#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_TEXT_SUPPORTED
#define PNG_TIME_RFC1123_SUPPORTED
#define PNG_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_USER_CHUNKS_SUPPORTED
#define PNG_USER_LIMITS_SUPPORTED
#define PNG_USER_MEM_SUPPORTED
#define PNG_USER_TRANSFORM_INFO_SUPPORTED
#define PNG_USER_TRANSFORM_PTR_SUPPORTED
#define PNG_WARNINGS_SUPPORTED
/*
#define PNG_WRITE_16BIT_SUPPORTED
#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_WRITE_BGR_SUPPORTED
#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
#define PNG_WRITE_FILLER_SUPPORTED
#define PNG_WRITE_FILTER_SUPPORTED
#define PNG_WRITE_FLUSH_SUPPORTED
#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
#define PNG_WRITE_INTERLACING_SUPPORTED
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
#define PNG_WRITE_INVERT_SUPPORTED
#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
#define PNG_WRITE_PACKSWAP_SUPPORTED
#define PNG_WRITE_PACK_SUPPORTED
#define PNG_WRITE_SHIFT_SUPPORTED
#define PNG_WRITE_SUPPORTED
#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
#define PNG_WRITE_SWAP_SUPPORTED
#define PNG_WRITE_TEXT_SUPPORTED
#define PNG_WRITE_TRANSFORMS_SUPPORTED
#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#define PNG_WRITE_bKGD_SUPPORTED
#define PNG_WRITE_cHRM_SUPPORTED
#define PNG_WRITE_eXIf_SUPPORTED
#define PNG_WRITE_gAMA_SUPPORTED
#define PNG_WRITE_hIST_SUPPORTED
#define PNG_WRITE_iCCP_SUPPORTED
#define PNG_WRITE_iTXt_SUPPORTED
#define PNG_WRITE_oFFs_SUPPORTED
#define PNG_WRITE_pCAL_SUPPORTED
#define PNG_WRITE_pHYs_SUPPORTED
#define PNG_WRITE_sBIT_SUPPORTED
#define PNG_WRITE_sCAL_SUPPORTED
#define PNG_WRITE_sPLT_SUPPORTED
#define PNG_WRITE_sRGB_SUPPORTED
#define PNG_WRITE_tEXt_SUPPORTED
#define PNG_WRITE_tIME_SUPPORTED
#define PNG_WRITE_tRNS_SUPPORTED
#define PNG_WRITE_zTXt_SUPPORTED
*/
#define PNG_bKGD_SUPPORTED
#define PNG_cHRM_SUPPORTED
#define PNG_eXIf_SUPPORTED
#define PNG_gAMA_SUPPORTED
#define PNG_hIST_SUPPORTED
#define PNG_iCCP_SUPPORTED
#define PNG_iTXt_SUPPORTED
#define PNG_oFFs_SUPPORTED
#define PNG_pCAL_SUPPORTED
#define PNG_pHYs_SUPPORTED
#define PNG_sBIT_SUPPORTED
#define PNG_sCAL_SUPPORTED
#define PNG_sPLT_SUPPORTED
#define PNG_sRGB_SUPPORTED
#define PNG_tEXt_SUPPORTED
#define PNG_tIME_SUPPORTED
#define PNG_tRNS_SUPPORTED
#define PNG_zTXt_SUPPORTED
/* end of options */
/* apng */
#define PNG_APNG_SUPPORTED
#define PNG_READ_APNG_SUPPORTED
/*#undef PNG_WRITE_APNG_SUPPORTED*/
/* end of apng */
/* settings */
#define PNG_API_RULE 0
#define PNG_DEFAULT_READ_MACROS 1
#define PNG_GAMMA_THRESHOLD_FIXED 5000
#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE
#define PNG_INFLATE_BUF_SIZE 1024
#define PNG_LINKAGE_API extern
#define PNG_LINKAGE_CALLBACK extern
#define PNG_LINKAGE_DATA extern
#define PNG_LINKAGE_FUNCTION extern
#define PNG_MAX_GAMMA_8 11
#define PNG_QUANTIZE_BLUE_BITS 5
#define PNG_QUANTIZE_GREEN_BITS 5
#define PNG_QUANTIZE_RED_BITS 5
#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
#define PNG_TEXT_Z_DEFAULT_STRATEGY 0
#define PNG_USER_CHUNK_CACHE_MAX 1000
#define PNG_USER_CHUNK_MALLOC_MAX 8000000
#define PNG_USER_HEIGHT_MAX 1000000
#define PNG_USER_WIDTH_MAX 1000000
#define PNG_ZBUF_SIZE 8192
#define PNG_ZLIB_VERNUM 0 /* unknown */
#define PNG_Z_DEFAULT_COMPRESSION (-1)
#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0
#define PNG_Z_DEFAULT_STRATEGY 1
#define PNG_sCAL_PRECISION 5
#define PNG_sRGB_PROFILE_CHECKS 2
/* end of settings */
#endif /* PNGLCONF_H */


code:
# Copyright 2018 Hippo Seven
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 3.4.1)
project(image-test C)

add_library(check STATIC IMPORTED)
set_target_properties(check PROPERTIES IMPORTED_LOCATION
    ${CMAKE_CURRENT_SOURCE_DIR}/check/${ANDROID_ABI}/lib/libcheck.a)

add_library(image-test SHARED
    native_test.c
    test_utils.c
    test_image_utils.c
    test_buffer.c
)
target_link_libraries(image-test PRIVATE image check log)
target_include_directories(image-test PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/javah
    ${CMAKE_CURRENT_SOURCE_DIR}/..
    ${CMAKE_CURRENT_SOURCE_DIR}/../image
    ${CMAKE_CURRENT_SOURCE_DIR}/check/${ANDROID_ABI}/include
)

repo_name: tachiyomiorg/mirror

license: mit


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>

#include "com_hippo_image_NativeTest.h"
#include "test_utils.h"
#include "test_image_utils.h"
#include "test_buffer.h"

JNIEXPORT jint JNICALL Java_com_hippo_image_NativeTest_nativeTestNative(
    JNIEnv* env,
    jclass __unused clazz,
    jstring temp_dir,
    jstring log_file
) {
  Suite* suite;
  SRunner* runner;
  const char *c_temp_dir;
  const char *c_log_file;
  int number_failed;

  c_temp_dir = (*env)->GetStringUTFChars(env, temp_dir, NULL);
  c_log_file = (*env)->GetStringUTFChars(env, log_file, NULL);

  // Check use system temporary directory to cache files.
  // But on Android, the app don't have permissions to
  // create file in system temporary directory.
  // So change the environmental variable to app-level temporary directory.
  setenv("TEMP", c_temp_dir, 1);

  suite = suite_create("Native");
  suite_add_tcase(suite, utils_case());
  suite_add_tcase(suite, image_utils_case());
  suite_add_tcase(suite, buffer_case());

  runner = srunner_create(suite);
  srunner_set_xml(runner, c_log_file);
  srunner_run_all(runner, CK_SILENT);
  number_failed = srunner_ntests_failed(runner);
  srunner_free(runner);

  (*env)->ReleaseStringUTFChars(env, temp_dir, c_temp_dir);
  (*env)->ReleaseStringUTFChars(env, log_file, c_log_file);

  return number_failed;
}


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <malloc.h>

#include "test_buffer.h"
#include "stream/buffer.h"

START_TEST(test_buffer_new) {
    Buffer* buffer = buffer_new(8, false);
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(0, buffer->length);
    ck_assert_int_eq(8, buffer->capacity);
    buffer_close(&buffer);

    ck_assert_ptr_null(buffer_new(0, false));
  }
END_TEST

START_TEST(test_buffer_new_from_raw) {
    void* raw = malloc(8);
    Buffer* buffer = buffer_new_from_raw(raw, 0, 8, 8, false);
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(8, buffer->length);
    ck_assert_int_eq(8, buffer->capacity);
    buffer_close(&buffer);

    raw = malloc(8);
    ck_assert_ptr_null(buffer_new_from_raw(NULL, 0, 1, 2, false));
    ck_assert_ptr_null(buffer_new_from_raw(raw, 2, 1, 2, false));
    ck_assert_ptr_null(buffer_new_from_raw(raw, 0, 3, 2, false));
    ck_assert_ptr_null(buffer_new_from_raw(raw, 0, 0, 0, false));
    free(raw);
  }
END_TEST

START_TEST(test_buffer_read) {
    Buffer* buffer = buffer_new(8, false);
    void* src = malloc(4);
    void* dst = malloc(4);
    *((uint*) src) = 0x01234567U;
    *((uint*) dst) = 0x76543210U;

    ck_assert_int_eq(0, buffer_read(buffer, dst, 4));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(0, buffer->length);
    ck_assert_int_eq(8, buffer->capacity);

    buffer_write(buffer, src, 4);
    ck_assert_int_eq(2, buffer_read(buffer, dst, 2));
    ck_assert_mem_eq(src, dst, 2);
    ck_assert_int_eq(2, buffer->position);
    ck_assert_int_eq(4, buffer->length);
    ck_assert_int_eq(8, buffer->capacity);

    ck_assert_int_eq(2, buffer_read(buffer, dst + 2, 4));
    ck_assert_mem_eq(src, dst, 4);
    ck_assert_int_eq(4, buffer->position);
    ck_assert_int_eq(4, buffer->length);
    ck_assert_int_eq(8, buffer->capacity);

    buffer_close(&buffer);
  }
END_TEST

START_TEST(test_buffer_write_not_extendable) {
    Buffer* buffer = buffer_new(4, false);
    void* src = malloc(4);
    *((uint*) src) = 0x01234567U;

    ck_assert_int_eq(2, buffer_write(buffer, src, 2));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(2, buffer->length);
    ck_assert_int_eq(4, buffer->capacity);

    ck_assert_int_eq(2, buffer_write(buffer, src + 2, 3));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(4, buffer->length);
    ck_assert_int_eq(4, buffer->capacity);

    ck_assert_int_eq(0, buffer_write(buffer, src + 2, 3));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(4, buffer->length);
    ck_assert_int_eq(4, buffer->capacity);

    buffer_close(&buffer);
  }
END_TEST

START_TEST(test_buffer_write_extendable) {
    Buffer* buffer = buffer_new(2, true);
    void* src = malloc(4);
    *((uint*) src) = 0x01234567U;

    ck_assert_int_eq(2, buffer_write(buffer, src, 2));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(2, buffer->length);
    ck_assert_int_eq(2, buffer->capacity);

    ck_assert_int_eq(2, buffer_write(buffer, src + 2, 2));
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(4, buffer->length);
    ck_assert_int_eq(4, buffer->capacity);

    buffer_close(&buffer);
  }
END_TEST

START_TEST(test_buffer_seek) {
    Buffer* buffer = buffer_new(4, false);
    void* src = malloc(4);
    *((uint*) src) = 0x01234567U;
    buffer_write(buffer, src, 2);

    ck_assert_int_eq(1, buffer_seek(buffer, 1));
    ck_assert_int_eq(1, buffer->position);

    ck_assert_int_eq(0, buffer_seek(buffer, 0));
    ck_assert_int_eq(0, buffer->position);

    ck_assert_int_eq(2, buffer_seek(buffer, 3));
    ck_assert_int_eq(2, buffer->position);

    buffer_close(&buffer);
  }
END_TEST

START_TEST(test_buffer_shrink) {
    Buffer* buffer = buffer_new(4, false);
    void* src = malloc(4);
    void* dst = malloc(2);
    *((uint*) src) = 0x01234567U;

    buffer_write(buffer, src, 4);
    buffer_read(buffer, dst, 2);
    buffer_shrink(buffer);

    ck_assert_mem_eq(src + 2, buffer->raw, 2);
    ck_assert_int_eq(0, buffer->position);
    ck_assert_int_eq(2, buffer->length);
    ck_assert_int_eq(4, buffer->capacity);

    buffer_close(&buffer);
  }
END_TEST

TCase* buffer_case() {
  TCase* t_case = tcase_create("Buffer");

  tcase_add_test(t_case, test_buffer_new);
  tcase_add_test(t_case, test_buffer_new_from_raw);
  tcase_add_test(t_case, test_buffer_read);
  tcase_add_test(t_case, test_buffer_write_not_extendable);
  tcase_add_test(t_case, test_buffer_write_extendable);
  tcase_add_test(t_case, test_buffer_seek);
  tcase_add_test(t_case, test_buffer_shrink);

  return t_case;
}


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_TEST_BUFFER_H
#define IMAGE_TEST_BUFFER_H

#include <check.h>

TCase* buffer_case();

#endif //IMAGE_TEST_BUFFER_H


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "test_image_utils.h"
#include "image_utils.h"

START_TEST(test_next_pow2_size_t) {
    ck_assert_int_eq(256, next_pow2_size_t(194));
    ck_assert_int_eq(256, next_pow2_size_t(255));
    ck_assert_int_eq(256, next_pow2_size_t(256));
    ck_assert_int_eq(512, next_pow2_size_t(257));
  }
END_TEST

TCase* image_utils_case() {
  TCase* t_case = tcase_create("ImageUtils");

  tcase_add_test(t_case, test_next_pow2_size_t);

  return t_case;
}


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_TEST_IMAGE_UTILS_H
#define IMAGE_TEST_IMAGE_UTILS_H

#include <check.h>

TCase* image_utils_case();

#endif //IMAGE_TEST_IMAGE_UTILS_H


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <malloc.h>

#include "test_utils.h"
#include "utils.h"

START_TEST(test_max) {
    ck_assert_int_eq(100, MAX(10, 100));
    ck_assert_int_eq(100, MAX(-10, 100));
  }
END_TEST

START_TEST(test_min) {
    ck_assert_int_eq(10, MIN(10, 100));
    ck_assert_int_eq(-10, MIN(-10, 100));
  }
END_TEST

START_TEST(test_clear) {
    void* block1 = malloc(100);
    void* block2 = calloc(1, 100);

    ck_assert_mem_ne(block1, block2, 100);

    CLEAR(block1, 100);
    ck_assert_mem_eq(block1, block2, 100);
  }
END_TEST

START_TEST(test_clear_null) {
    CLEAR(NULL, 100);
  }
END_TEST

TCase* utils_case() {
  TCase* t_case = tcase_create("Utils");

  tcase_add_test(t_case, test_max);
  tcase_add_test(t_case, test_min);
  tcase_add_test(t_case, test_clear);
  tcase_add_test(t_case, test_clear_null);

  return t_case;
}


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_TEST_UTILS_H
#define IMAGE_TEST_UTILS_H

#include <check.h>

TCase* utils_case();

#endif //IMAGE_TEST_UTILS_H


code:
/*
 * Copyright 2015 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef UTILS_H
#define UTILS_H

#define STRINGIZE(L) #L
#define MAKESTRING(M, L) M(L)

#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

#define CLEAR(p, n) if ((p) != NULL) memset((p), 0, (n))

#endif // UTILS_H


code:
# Copyright 2018 Hippo Seven
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 3.4.1)
project(image-webp C)

set(LIBWEBP_SOURCES
    image_webp.c
    libwebp/src/dec/alpha_dec.c
    libwebp/src/dec/buffer_dec.c
    libwebp/src/dec/frame_dec.c
    libwebp/src/dec/idec_dec.c
    libwebp/src/dec/io_dec.c
    libwebp/src/dec/quant_dec.c
    libwebp/src/dec/tree_dec.c
    libwebp/src/dec/vp8_dec.c
    libwebp/src/dec/vp8l_dec.c
    libwebp/src/dec/webp_dec.c
    libwebp/src/demux/anim_decode.c
    libwebp/src/demux/demux.c
    libwebp/src/dsp/alpha_processing.c
    libwebp/src/dsp/alpha_processing_mips_dsp_r2.c
    libwebp/src/dsp/alpha_processing_neon.c
    libwebp/src/dsp/alpha_processing_sse2.c
    libwebp/src/dsp/alpha_processing_sse41.c
    libwebp/src/dsp/cpu.c
    libwebp/src/dsp/dec.c
    libwebp/src/dsp/dec_clip_tables.c
    libwebp/src/dsp/dec_mips32.c
    libwebp/src/dsp/dec_mips_dsp_r2.c
    libwebp/src/dsp/dec_msa.c
    libwebp/src/dsp/dec_neon.c
    libwebp/src/dsp/dec_sse2.c
    libwebp/src/dsp/dec_sse41.c
    libwebp/src/dsp/filters.c
    libwebp/src/dsp/filters_mips_dsp_r2.c
    libwebp/src/dsp/filters_msa.c
    libwebp/src/dsp/filters_neon.c
    libwebp/src/dsp/filters_sse2.c
    libwebp/src/dsp/lossless.c
    libwebp/src/dsp/lossless_mips_dsp_r2.c
    libwebp/src/dsp/lossless_msa.c
    libwebp/src/dsp/lossless_neon.c
    libwebp/src/dsp/lossless_sse2.c
    libwebp/src/dsp/rescaler.c
    libwebp/src/dsp/rescaler_mips32.c
    libwebp/src/dsp/rescaler_mips_dsp_r2.c
    libwebp/src/dsp/rescaler_msa.c
    libwebp/src/dsp/rescaler_neon.c
    libwebp/src/dsp/rescaler_sse2.c
    libwebp/src/dsp/upsampling.c
    libwebp/src/dsp/upsampling_mips_dsp_r2.c
    libwebp/src/dsp/upsampling_msa.c
    libwebp/src/dsp/upsampling_neon.c
    libwebp/src/dsp/upsampling_sse2.c
    libwebp/src/dsp/upsampling_sse41.c
    libwebp/src/dsp/yuv.c
    libwebp/src/dsp/yuv_mips32.c
    libwebp/src/dsp/yuv_mips_dsp_r2.c
    libwebp/src/dsp/yuv_neon.c
    libwebp/src/dsp/yuv_sse2.c
    libwebp/src/dsp/yuv_sse41.c
    libwebp/src/utils/bit_reader_utils.c
    libwebp/src/utils/color_cache_utils.c
    libwebp/src/utils/filters_utils.c
    libwebp/src/utils/huffman_utils.c
    libwebp/src/utils/quant_levels_dec_utils.c
    libwebp/src/utils/random_utils.c
    libwebp/src/utils/rescaler_utils.c
    libwebp/src/utils/thread_utils.c
    libwebp/src/utils/utils.c
)
set(LIBWEBP_INCLUDES
    ${IMAGE_EXPORT_INCLUDES}
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/libwebp
)
set(LIBWEBP_DEFINITIONS
)
set(LIBWEBP_LIBRARIES
)

add_definitions(-DWEBP_SWAP_16BIT_CSP=1)

if(IMAGE_SINGLE_SHARED_LIB)
    # Compile a static library for image-singlelib
    set(LIBWEBP_LIBRARY_NAME image-webp-static)
    set(LIBWEBP_LIBRARY_TYPE STATIC)
    set(LIBWEBP_INCLUDES_VISIBILITY PUBLIC) # Share include dir with image project
else()
    # Compile a shared library to be imported by image-core
    set(LIBWEBP_LIBRARY_NAME image-webp)
    set(LIBWEBP_LIBRARY_TYPE SHARED)
    set(LIBWEBP_INCLUDES_VISIBILITY PRIVATE)

    # Link against image shared lib to get helper methods
    set(LIBWEBP_LIBRARIES
        ${LIBWEBP_LIBRARIES}
        image
        log
    )
endif()

add_library(${LIBWEBP_LIBRARY_NAME} ${LIBWEBP_LIBRARY_TYPE} ${LIBWEBP_SOURCES})
target_include_directories(${LIBWEBP_LIBRARY_NAME} ${LIBWEBP_INCLUDES_VISIBILITY}
${LIBWEBP_INCLUDES})
target_compile_definitions(${LIBWEBP_LIBRARY_NAME} PRIVATE ${LIBWEBP_DEFINITIONS})
target_link_libraries(${LIBWEBP_LIBRARY_NAME} PRIVATE ${LIBWEBP_LIBRARIES})


code:
/*
 * Copyright 2015 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <image_info.h>

#include "image.h"
#include "image_webp.h"
#include "image_utils.h"
#include "image_decoder.h"
#include "image_convert.h"
#include "animated_image.h"
#include "../log.h"

#define IMAGE_WEBP_PREPARE_NONE 0x00
#define IMAGE_WEBP_PREPARE_BACKGROUND 0x01

typedef struct {
    uint32_t width;
    uint32_t height;
    uint32_t offset_x;
    uint32_t offset_y;
    uint32_t delay; // ms
    WebPMuxAnimDispose disposal;
    WebPMuxAnimBlend blend;
    uint8_t prepare;
    uint8_t* buffer;
} WebPFrame;

typedef struct {
    WebPFrame* frames;
    uint32_t frame_count;
    uint32_t background_color;
    Stream* stream;
    WebPDemuxer *demux;
    WebPIterator *iterator;
} WebPAnimData;

LIBRARY_EXPORT
bool webp_init(ImageLibrary* library) {
    library->loaded = true;
    library->is_magic = webp_is_magic;
    library->decode = webp_decode;
    library->decode_info = webp_decode_info;
    library->decode_buffer = webp_decode_buffer;
    library->create = NULL;
    library->get_description = webp_get_description;

    return true;
}

bool webp_is_magic(Stream* stream) {
    uint8_t magic[2];

    size_t read = stream->peek(stream, magic, sizeof(magic));
    if (read != sizeof(magic)) {
        LOGE(MSG("Could not read %zu bytes from stream, only read %zu"), sizeof(magic), read);
        return false;
    }

    return magic[0] == IMAGE_WEBP_MAGIC_NUMBER_0 && magic[1] == IMAGE_WEBP_MAGIC_NUMBER_1;
}

const char* webp_get_description() {
    return IMAGE_WEBP_DECODER_DESCRIPTION;
}

static inline void blend_over(uint8_t* dp, const uint8_t* sp, size_t len) {
    uint32_t i;
    uint32_t u, v, al;

    for (i = 0; i < len; i += 4, sp += 4, dp += 4) {
        if (sp[3] == 255) {
            memcpy(dp, sp, 4);
        } else if (sp[3] != 0) {
            if (dp[3] != 0) {
                u = sp[3] * 255u;
                v = (255u - sp[3]) * dp[3];
                al = u + v;
                dp[0] = (uint8_t) ((sp[0] * u + dp[0] * v) / al);
                dp[1] = (uint8_t) ((sp[1] * u + dp[1] * v) / al);
                dp[2] = (uint8_t) ((sp[2] * u + dp[2] * v) / al);
                dp[3] = (uint8_t) (al / 255u);
            } else {
                memcpy(dp, sp, 4);
            }
        }
    }
}

static void blend(uint8_t* dst, uint32_t dst_width, uint32_t dst_height,
                  uint8_t* src, uint32_t src_width, uint32_t src_height,
                  uint32_t offset_x, uint32_t offset_y, bool blend_op_over) {
    uint32_t i;
    uint8_t* src_ptr;
    uint8_t* dst_ptr;
    size_t len;
    uint32_t copy_width = MIN(dst_width - offset_x, src_width);
    uint32_t copy_height = MIN(dst_height - offset_y, src_height);

    for (i = 0; i < copy_height; i++) {
        src_ptr = src + (i * src_width * 4);
        dst_ptr = dst + (((offset_y + i) * dst_width + offset_x) * 4);
        len = (size_t) (copy_width * 4);

        if (blend_op_over) {
            blend_over(dst_ptr, src_ptr, len);
        } else {
            memcpy(dst_ptr, src_ptr, len);
        }
    }
}

static void read_frame(WebPIterator *iter, WebPFrame *frame, WebPFrame *pre_frame) {
    frame->buffer = WebPDecodeRGBA(iter->fragment.bytes, iter->fragment.size, (int*) &frame->width, (int*) &frame->height);
    frame->offset_x = (uint32_t) iter->x_offset;
    frame->offset_y = (uint32_t) iter->y_offset;
    frame->delay = (uint32_t) iter->duration;
    frame->disposal = iter->dispose_method;
    frame->blend = iter->blend_method;

    WebPMuxAnimDispose pre_disposal = pre_frame != NULL ? pre_frame->disposal : WEBP_MUX_DISPOSE_BACKGROUND;
    switch (pre_disposal) {
        case WEBP_MUX_DISPOSE_NONE:
            frame->prepare = IMAGE_WEBP_PREPARE_NONE;
            break;
        default:
        case WEBP_MUX_DISPOSE_BACKGROUND:
            frame->prepare = IMAGE_WEBP_PREPARE_BACKGROUND;
            break;
    }
}

static void free_frames(WebPFrame** frames, size_t count) {
    WebPFrame* frame_info;
    size_t i;

    if (frames == NULL || *frames == NULL) {
        return;
    }

    for (i = 0; i < count; i++) {
        frame_info = *frames + i;
        free(frame_info->buffer);
        frame_info->buffer = NULL;
    }
    free(*frames);
    *frames = NULL;
}

Stream *get_stream(AnimatedImage *image) {
    return ((WebPAnimData*) image->data)->stream;
}

void complete(AnimatedImage *image) {
    WebPAnimData* data = image->data;
    WebPFrame* frame;
    uint32_t i = 1;
    uint32_t j;

    if (image->completed || data->demux == NULL || data->iterator == NULL) {
        return;
    }

}

static uint32_t get_frame_count(AnimatedImage *image) {
    return ((WebPAnimData*) image->data)->frame_count;
}

uint32_t get_delay(AnimatedImage *image, uint32_t frame) {
    WebPAnimData* data = image->data;
    if (frame >= data->frame_count) {
        LOGE(MSG("Frame count is %ud, can't get delay of index %ud"), data->frame_count, frame);
        return 0;
    }
    return (data->frames + frame)->delay;
}

uint32_t get_byte_count(AnimatedImage *image) {
    uint32_t size = 0;
    uint32_t i;
    WebPFrame* frame;
    WebPAnimData* data = image->data;
    if (image->completed) {
        for (i = 0; i < data->frame_count; i++) {
            frame = data->frames + i;
            size += frame->width * frame->height * 4;
        }
        return size;
    } else {
        LOGE(MSG("Can't call get_byte_count on Uncompleted AnimatedImage"));
        return 0;
    }
}

void advance(AnimatedImage *image, DelegateImage *dImage) {
    WebPAnimData* data = image->data;
    int32_t target_index = dImage->index + 1;
    uint32_t width = image->width;
    uint32_t height = image->height;
    WebPFrame* frame;

    if (target_index < 0 || target_index >= data->frame_count) {
        target_index = 0;
    }
    if (target_index == dImage->index) {
        return;
    }

    frame = data->frames + target_index;

    // Prepare
    switch (frame->prepare) {
        case IMAGE_WEBP_PREPARE_NONE:
            // Do nothing
            break;
        default:
        case IMAGE_WEBP_PREPARE_BACKGROUND:
            // Set transparent
            memset(dImage->buffer, data->background_color, width * height * 4);
            break;
    }

    blend(dImage->buffer, dImage->width, dImage->height,
          frame->buffer, frame->width, frame->height, frame->offset_x, frame->offset_y,
          frame->blend == WEBP_MUX_BLEND);

    delegate_image_apply(dImage);

    dImage->index = target_index;
}

void recycle(AnimatedImage **image) {
    WebPAnimData *data;

    if (image == NULL || *image == NULL) {
        return;
    }

    data = (WebPAnimData*) (*image)->data;

    if (data->iterator != NULL) {
        WebPDemuxReleaseIterator(data->iterator);
        free(data->iterator);
        data->iterator = NULL;
    }
    if (data->demux != NULL) {
        WebPDemuxDelete(data->demux);
        data->demux = NULL;
    }

    if (data->stream != NULL) {
        data->stream->close(&data->stream);
        data->stream = NULL;
    }

    free(data);
    (*image)->data = NULL;

    free(*image);
    *image = NULL;
}

void* webp_decode(Stream* stream, bool partially, bool* animated) {
    void* result = NULL;
    StaticImage* static_image = NULL;
    AnimatedImage* animated_image = NULL;
    WebPAnimData* webp_anim_data = NULL;
    WebPDemuxer *demux = NULL;
    WebPIterator *iter = NULL;
    WebPFrame *frames = NULL;

    size_t data_size = 0;
    uint32_t frame_count = 1;
    uint32_t background_color = 0;
    uint32_t width;
    uint32_t height;

    uint8_t *data = stream_read_all(stream, &data_size);
    if (data == NULL) {
        WTF_OOM;
        return NULL;
    }

    // Get features
    WebPBitstreamFeatures features;
    if (WebPGetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
        LOGW("Invalid webp info");
        goto end;
    }

    width = (uint32_t) features.width;
    height = (uint32_t) features.height;

    // Init demuxer if the image is animated
    if (features.has_animation) {
        WebPData webp_data = {.bytes = data, .size = data_size};
        demux = WebPDemux(&webp_data);

        frame_count = WebPDemuxGetI(demux, WEBP_FF_FRAME_COUNT);
        background_color = WebPDemuxGetI(demux, WEBP_FF_BACKGROUND_COLOR);
    }

    // Check there's at least one frame
    if (frame_count == 0) {
        LOGW("Invalid frame count");
        goto end;
    }

    // If only one frame, decode all
    if (frame_count == 1) {
        partially = false;
    }

    if (features.has_animation) {
        // Malloc iterator and frames
        iter = (WebPIterator*) malloc(sizeof(WebPIterator));
        frames = (WebPFrame*) malloc(frame_count * sizeof(WebPFrame));
        if (iter == NULL || frames == NULL) {
            WTF_OOM;
            goto end;
        }

        // Set frame buffer NULL for safety
        for (int i = 0; i < frame_count; i++) {
            (frames + i)->buffer = NULL;
        }

        // Init iterator
        if (!WebPDemuxGetFrame(demux, 1, iter)) {
            goto end;
        }

        // Read first frame
        read_frame(iter, frames, NULL);

        // Read remaining frames if not partial
        if (!partially) {
            for (int i = 1; i < frame_count; i++) {
                if (WebPDemuxNextFrame(iter)) {
                    read_frame(iter, frames + i, frames + i - 1);
                }
            }
        }

        if (frame_count == 1) {
            // For one-frame webp, use StaticImage
            static_image = static_image_new(width, height);
            if (static_image == NULL) {
                WTF_OOM;
                goto end;
            }
            memset(static_image->buffer, background_color, width * height * 4);
            blend(static_image->buffer, width, height,
                  frames->buffer, frames->width, frames->height,
                  frames->offset_x, frames->offset_y, false);

            // Free frames, don't need it anymore
            free_frames(&frames, 1);

            // Set final result
            static_image->format = IMAGE_FORMAT_WEBP;
            static_image->opaque = !features.has_alpha;
            *animated = false;
            result = static_image;
            goto end;
        } else {
            // For multi-frame webp, use AnimatedImage
            animated_image = (AnimatedImage *) malloc(sizeof(AnimatedImage));
            webp_anim_data = (WebPAnimData *) malloc(sizeof(WebPAnimData));
            if (animated_image == NULL || webp_anim_data == NULL) {
                WTF_OOM;
                goto end;
            }

            animated_image->width = width;
            animated_image->height = height;
            animated_image->format = IMAGE_FORMAT_WEBP;
            animated_image->opaque = !features.has_alpha;
            animated_image->completed = !partially;
            animated_image->data = webp_anim_data;

            animated_image->get_stream = &get_stream;
            animated_image->complete = &complete;
            animated_image->get_frame_count = &get_frame_count;
            animated_image->get_delay = &get_delay;
            animated_image->get_byte_count = &get_byte_count;
            animated_image->advance = &advance;
            animated_image->recycle = &recycle;

            webp_anim_data->frames = frames;
            webp_anim_data->frame_count = frame_count;
            webp_anim_data->background_color = background_color;

            if (partially) {
                webp_anim_data->stream = stream;
                webp_anim_data->iterator = iter;
                webp_anim_data->demux = demux;
            } else {
                webp_anim_data->stream = NULL;
                webp_anim_data->iterator = NULL;
                webp_anim_data->demux = NULL;
            }

            *animated = true;
            result = animated_image;
            goto end;
        }
    } else {
        // New static image
        static_image = static_image_new(width, height);
        if (static_image == NULL) {
            goto end;
        }

        int row_size = features.width * 4;
        size_t total_size = (size_t) (features.height * row_size);

        // Start decompress
        WebPDecodeRGBAInto(data, data_size, static_image->buffer, total_size, row_size);

        static_image->format = IMAGE_FORMAT_WEBP;
        static_image->opaque = !features.has_alpha;
        result = static_image;
        goto end;
    }

    end:

    if (!partially || result == NULL) {
        WebPDemuxReleaseIterator(iter);
        free(iter);
        WebPDemuxDelete(demux);
    }

    if (result == NULL) {
        free_frames(&frames, frame_count);
        free(animated_image);
        free(webp_anim_data);
        free(static_image);
        if (stream != NULL) {
            stream->close(&stream);
        }
    }

    return result;
}

bool webp_decode_info(Stream* stream, ImageInfo* info) {
    size_t bytes_to_read = 30;
    uint8_t data[bytes_to_read];

    stream->read(stream, data, bytes_to_read);

    WebPBitstreamFeatures features;
    if (WebPGetFeatures(data, bytes_to_read, &features) != VP8_STATUS_OK) {
        LOGE("Failed to parse webp");
        return false;
    }

    info->width = (uint32_t) features.width;
    info->height = (uint32_t) features.height;
    info->opaque = !features.has_alpha;

    return true;
}

bool webp_decode_buffer(Stream* stream, bool clip, uint32_t x, uint32_t y, uint32_t width,
                        uint32_t height, int32_t config, uint32_t ratio, BufferContainer* container) {

    bool result = false;
    uint8_t* d_buffer = NULL;

    uint32_t d_width;
    uint32_t d_height;

    // Init a configuration object
    WebPDecoderConfig webp_config;
    if (!WebPInitDecoderConfig(&webp_config)) {
        return false;
    }

    // Read the data from the stream
    size_t buffer_size = 0;
    uint8_t *buffer = stream_read_all(stream, &buffer_size);

    // Set clip info
    if (!clip) {
        // Read image headers
        uint32_t image_width = 0, image_height = 0;

        if (!WebPGetInfo(buffer, buffer_size, (int *) &image_width, (int *) &image_height)) {
            goto end;
        }

        // Decode full image
        x = 0; y = 0; width = image_width; height = image_height;
    }

    // Set config to IMAGE_CONFIG_RGB_565 as default
    if (config == IMAGE_CONFIG_AUTO) {
        config = IMAGE_CONFIG_RGB_565;
    }

    // Set out color space
    if (config == IMAGE_CONFIG_RGBA_8888) {
        webp_config.output.colorspace = MODE_RGBA;
    } else if (config == IMAGE_CONFIG_RGB_565) {
        webp_config.output.colorspace = MODE_RGB_565;
    } else {
        LOGE("Invalid config: %d", config);
        goto end;
    }

    // Fix width and height
    width = floor_uint32_t(width, ratio);
    height = floor_uint32_t(height, ratio);
    d_width = width / ratio;
    d_height = height / ratio;

    if (d_width == 0 || d_height == 0) {
        LOGE("Ratio is too large!");
        result = true;
        goto end;
    }

    // Set region to decode
    webp_config.options.use_cropping = clip;
    webp_config.options.crop_left = x;
    webp_config.options.crop_top = y;
    webp_config.options.crop_width = width;
    webp_config.options.crop_height = height;

    // Set scaled size
    webp_config.options.use_scaling = ratio != 1;
    webp_config.options.scaled_width = d_width;
    webp_config.options.scaled_height = d_height;

    // Create buffer
    d_buffer = container->create_buffer(container, d_width, d_height, config);
    if (d_buffer == NULL) { goto end; }

    uint32_t row_size = d_width * get_depth_for_config(config);

    // Save decoded data in external buffer
    webp_config.output.u.RGBA.rgba = d_buffer;
    webp_config.output.u.RGBA.size = row_size * d_height;
    webp_config.output.u.RGBA.stride = row_size;
    webp_config.output.is_external_memory = 1;

    // Decode image
    WebPDecode(buffer, buffer_size, &webp_config);

    result = true;

    end:
    if (d_buffer != NULL) {
        container->release_buffer(container, d_buffer);
    }

    WebPFreeDecBuffer(&webp_config.output);

    return result;
}


code:
/*
 * Copyright 2015 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_IMAGE_WEBP_H
#define IMAGE_IMAGE_WEBP_H

#include <stdbool.h>

#include "src/webp/decode.h"
#include "src/webp/mux_types.h"
#include "src/webp/demux.h"
#include "image_library.h"
#include "stream.h"

#define IMAGE_WEBP_DECODER_DESCRIPTION ("libwebp " MAKESTRING(STRINGIZE, DEC_MAJ_VERSION) "." \
                                        MAKESTRING(STRINGIZE, DEC_MIN_VERSION) "." \
                                        MAKESTRING(STRINGIZE, DEC_REV_VERSION))

#define IMAGE_WEBP_MAGIC_NUMBER_0 0x52
#define IMAGE_WEBP_MAGIC_NUMBER_1 0x49

bool webp_init(ImageLibrary* library);

bool webp_is_magic(Stream* stream);

const char* webp_get_description();

void* webp_decode(Stream* stream, bool partially, bool* animated);

bool webp_decode_info(Stream* stream, ImageInfo* info);

bool webp_decode_buffer(Stream* stream, bool clip, uint32_t x, uint32_t y, uint32_t width,
                       uint32_t height, int32_t config, uint32_t ratio, BufferContainer* container);

#endif // IMAGE_IMAGE_WEBP_H


code:
package com.hippo.image;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * To work on unit tests, switch the Test Artifact in the Build Variants view.
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, 2 + 2);
    }
}


code:
/*
 * Copyright 2018 Hippo Seven
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import org.apache.tools.ant.taskdefs.condition.Os

apply plugin: 'com.android.library'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    sourceSets {
        main {
            java.srcDirs = ['../src/main/java']
            manifest.srcFile '../src/main/AndroidManifest.xml'
        }
        androidTest {
            java.srcDirs = ['../src/androidTest/java']
        }
    }

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        externalNativeBuild {
            cmake {
                targets "image-test"
                arguments "-DANDROID_ARM_NEON=TRUE",
                          "-DIMAGE_SINGLE_SHARED_LIB=TRUE"
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), '../proguard-rules.pro'
        }
    }

    externalNativeBuild {
        cmake {
            path '../src/main/jni/CMakeLists.txt'
        }
    }
}

clean {
    delete '../src/main/jni/test/javah'
}

task javah(type: Exec, dependsOn: 'compileDebugAndroidTestJavaWithJavac') {
    char separator = Os.isFamily(Os.FAMILY_WINDOWS) ? ';' : ':'
    commandLine 'javah', '-jni',
            '-d', '../src/main/jni/test/javah',
            '-cp', "${android.getSdkDirectory().getAbsolutePath()}/platforms/android-${rootProject.ext.targetSdkVersion}/android.jar${separator}build/intermediates/javac/debugAndroidTest/compileDebugAndroidTestJavaWithJavac/classes",
            'com.hippo.image.NativeTest'
    inputs.dir('../src/androidTest/java')
    outputs.dir('../src/main/jni/test/javah')
}

dependencies {
    implementation "com.android.support:support-annotations:${rootProject.ext.supportLibraryVersion}"
    testImplementation "junit:junit:${rootProject.ext.junitVersion}"
    androidTestImplementation "com.android.support.test:runner:${rootProject.ext.androidTestRunnerVersion}"
    androidTestImplementation "org.jsoup:jsoup:${rootProject.ext.jsoupVersion}"
}

project.afterEvaluate {
    externalNativeBuildDebug.dependsOn ':singlelib:javah', javah
    externalNativeBuildRelease.dependsOn ':singlelib:javah', javah
}


code:
apply plugin: 'com.android.library'

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion

    sourceSets {
        main {
            java.srcDirs = []
            manifest.srcFile 'AndroidManifest.xml'
        }
    }

    packagingOptions {
        // Do not include libimage.so in the codec aar
        exclude '**/libimage.so'
    }

    defaultConfig {
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode rootProject.ext.versionCode
        versionName rootProject.ext.versionName

        externalNativeBuild {
            cmake {
                targets "image-webp"
                arguments "-DANDROID_ARM_NEON=TRUE",
                          "-DIMAGE_SINGLE_SHARED_LIB=FALSE"
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), '../proguard-rules.pro'
        }
    }

    externalNativeBuild {
        cmake {
            path '../src/main/jni/CMakeLists.txt'
        }
    }
}

project.afterEvaluate {
    externalNativeBuildDebug.dependsOn ':singlelib:javah'
    externalNativeBuildRelease.dependsOn ':singlelib:javah'
}

// Publish arr without java source and java doc
apply plugin: 'com.github.dcendents.android-maven'


code:
include ':app'

include ':core', ':gif', ':jpeg', ':png', ':webp'
project(':core').projectDir = new File('library/core')
project(':gif').projectDir = new File('library/gif')
project(':jpeg').projectDir = new File('library/jpeg')
project(':png').projectDir = new File('library/png')
project(':webp').projectDir = new File('library/webp')

include ':singlelib'
project(':singlelib').projectDir = new File('library/singlelib')

include ':test'
project(':test').projectDir = new File('library/test')


code:
* Programming, inbuilt puzzles, art, sounds, pixel demake of GBA Jam 2022 logo -- [kva64] (*code distributed under zlib license, art and sounds - CC BY 4.0*)
* Engine -- Butano by [GValiente](https://github.com/gvaliente) (*zlib license with multiple attributes* (see *licenses* folder))
* Music -- *Which Brand Of Mustard Shall I Buy* by [congusbongus](https://modarchive.org/index.php?request=view_profile&query=85757) (*CC0 license*)
* Original GBA Jam 2022 logo designs -- [foopod/Jono Shields](https://foopod.itch.io), [exelotl](https://exelo.tl) (logo asset attributions can be found [here](https://gbajam22.github.io))


code:
#---------------------------------------------------------------------------------------------------------------------
# TARGET is the name of the output.
# BUILD is the directory where object files & intermediate files will be placed.
# LIBBUTANO is the main directory of butano library (https://github.com/GValiente/butano).
# PYTHON is the path to the python interpreter.
# SOURCES is a list of directories containing source code.
# INCLUDES is a list of directories containing extra header files.
# DATA is a list of directories containing binary data.
# GRAPHICS is a list of directories containing files to be processed by grit.
# AUDIO is a list of directories containing files to be processed by mmutil.
# ROMTITLE is a uppercase ASCII, max 12 characters text string containing the output ROM title.
# ROMCODE is a uppercase ASCII, max 4 characters text string containing the output ROM code.
# USERFLAGS is a list of additional compiler flags:
#     Pass -flto to enable link-time optimization.
#     Pass -O0 to improve debugging.
# USERLIBDIRS is a list of additional directories containing libraries.
#     Each libraries directory must contains include and lib subdirectories.
# USERLIBS is a list of additional libraries to link with the project.
# USERBUILD is a list of additional directories to remove when cleaning the project.
# EXTTOOL is an optional command executed before processing audio, graphics and code files.
#
# All directories are specified relative to the project directory where the makefile is found.
#---------------------------------------------------------------------------------------------------------------------
TARGET      :=  $(notdir $(CURDIR))
BUILD       :=  build
LIBBUTANO   :=  ../butano/butano
PYTHON      :=  python
SOURCES     :=  src
INCLUDES    :=  include
DATA        :=
GRAPHICS    :=  graphics
AUDIO       :=  audio
ROMTITLE    :=  NOTENOGRAM
ROMCODE     :=  NGRM
USERFLAGS   :=
USERLIBDIRS :=
USERLIBS    :=
USERBUILD   :=
EXTTOOL     :=

#---------------------------------------------------------------------------------------------------------------------
# Export absolute butano path:
#---------------------------------------------------------------------------------------------------------------------
ifndef LIBBUTANOABS
	export LIBBUTANOABS	:=	$(realpath $(LIBBUTANO))
endif

#---------------------------------------------------------------------------------------------------------------------
# Include main makefile:
#---------------------------------------------------------------------------------------------------------------------
include $(LIBBUTANOABS)/butano.mak

path: Makefile


code:
# notenogram
### (read as note-nogram)
Chill analog-styled Gameboy Advance picross/nonogram/hanjie/griddler game made with [Butano](http://https://github.com/GValiente/butano) for [GBA Jam 2022](http://https://itch.io/jam/gbajam22), with some gameplay elements inspired by [Battle Picross by Sean Reid](https://pdroms.de/files/nintendo-gameboyadvance-gba/battle-picross-v1-0).

## Features (WIP, subject to change):
* 21 original 12x12 picross puzzles to solve
* cringy Japanese anime girl voice clips provided by me
* fancy bossanova module music *not* made by me (not now at least)
* story mode that puts one's strategy skills to the test and has three different endings based on said skills
* tutorial mode that explains picross basics and some solving strategies
* creator mode that allows making puzzles and sharing them via GBA save files (*any* save files)
* more original character cameos?

## Controls:
* **A button** - color the square the pen cursor is pointing at/confirm menu option/skip text
* **B button** - cross out the square/exit menu
* **D-pad** - move the cursor (*hint: pressing and holding a directional key while holding A or B on the picross grid will mark otherwise empty squares as either "on" or "off" in the selected direction*)
* **Select** - exit puzzle screen
* **Start (in creator mode)** - write current puzzle to SRAM
* **L or R button (in creator mode)** - switch custom puzzle slots in SRAM to write to (only three slots available for now, writing to a full slot will overwrite its contents)

## Issues
* VBA-M saves not being written to during gameplay - FIXED (probably, done by updating to latest Butano version)
* Broken font on exiting to main menu state - FIXED, now to prevent any shallow copies of bn::sprite\_text\_generator pointers

## TODO
* Completely replace boolean arrays with unsigned integers for quicker reads, writes and condition checks (*pending, reduces ROM size by about 2kB, but makes mistake detection harder to implement*)
* Figure out how to design the main game state interface class to avoid any chaos in overridden methods and simplify game loop coding (and reduce used backgrounds)
* Update story mode with better graphics and more exclusive puzzles
* Create a tiny app for converting hex data/image files into game code-readable data
* Add option menu for customizing visuals and gameplay
* Make some lo-fi tracker beats to solve griddlers to
* Bwehh


code:
#ifndef FADE_TRANSPARENCY_EFFECTS_H
#define FADE_TRANSPARENCY_EFFECTS_H

#include "bn_array.h"
#include "bn_blending_actions.h"
#include "bn_blending_fade_alpha.h"
#include "bn_blending_fade_alpha_hbe_ptr.h"
#include "bn_blending_transparency_attributes.h"
#include "bn_blending_transparency_attributes_hbe_ptr.h"
#include "bn_core.h"

namespace fx
{
    void introLogoFade(int&);
    void simpleFade(int&, bool);
    void hBlankFade(int&, bool);
}

#endif // FADE_TRANSPARENCY_EFFECTS_H


code:
#ifndef GAME_LOOP_H
#define GAME_LOOP_H

#include "fade_transparency_effects.h"
#include "state_free_play_menu.h"
#include "state_main.h"
#include "state_main_timed.h"
#include "state_start_menu.h"
#include "state_story.h"
#include "state_tutorial.h"

#include "dt_8x8_variable.h"

namespace loop
{
    void solve_puzzle(bn::array<bool, 144> const&);
    int solve_arcade_puzzle();
    void select_puzzle(bn::sprite_text_generator*);
    void make_puzzle(bn::sprite_text_generator*);
    void init_story_mode(bn::sprite_text_generator*);
    void init_tutorial_mode(bn::sprite_text_generator*);
    void menu();
}

#endif // GAME_LOOP_H


code:
#ifndef PICROSS_GRID_H
#define PICROSS_GRID_H

#include <bn_array.h>
#include <bn_fixed_point.h>
#include "bn_keypad.h"
#include "bn_vector.h"

#include "bn_sound_items.h"

#include "bn_regular_bg_ptr.h"
#include "bn_regular_bg_map_ptr.h"
#include "bn_regular_bg_map_cell_info.h"

#include "tools.h"

class PicrossGrid
{
private:
    bn::array<bool, 144> grid;
    //bn::array<char, 18> grid_;

    bn::array<int, 2> cursor_position;
    static constexpr int screen_cell_upper_limit = 24;
    static constexpr int screen_cell_lower_limit = 13;

    int getCurrentGridIndex();
    //void markCell(int );
    //bool getCell(int);

public:

    bn::vector<int, 6*12> grid_hints_up;
    bn::vector<int, 6*12> grid_hints_left;
    bool creator_mode = false;

    PicrossGrid();

    int getCursorX();
    int getCursorY();

    bool processKeyInput(bn::regular_bg_map_cell&);
    bool processKeyContinuousInput(bn::regular_bg_map_cell&);
    bool processDPadInput();
    bool processDPadContinuousInput(int&);

    bn::array<bool, 144> const &getCurrentGrid();
    //bn::array<char, 18> const &getCurrentGrid();
    //redrawing number hints on the screen
    void updateHints(bn::array<bool, 144> const &);
    //void updateHints(bn::array<char, 18> const &);

    //cell checker for current cell, returns true if cell marked wrong
    bool checkCurrentCell(bn::array<bool, 144> const &);
    //bool checkCurrentCell(bn::array<char, 18> const &);
    //cell checker for the entire solution
    bool checkSolution(bn::array<bool, 144> const &);
    //bool checkSolution(bn::array<char, 18> const &);

    //set current play mode, should unlock various in-code stuff
    void solve();
    void create();

    void resetGrid();
    ~PicrossGrid();
};

#endif // PICROSS_GRID_H


code:
#ifndef STATE_BASE_H
#define STATE_BASE_H

#include "bn_blending_fade_alpha.h"
#include "bn_sprite_ptr.h"
#include "bn_regular_bg_builder.h"
#include "bn_sprite_builder.h"

#include "picross_grid.h"
#include "picross_solutions.h"
#include "tools.h"

#include "bn_regular_bg_items_square.h"
#include "bn_sprite_items_logo.h"

class GameState
{
    static constexpr int columns = 32;
    static constexpr int rows = 32;
    static constexpr int screen_cells = 32*32;
    int bg_x, bg_y;

    bn::regular_bg_map_cell cells[32*32];
    bn::regular_bg_map_item item;

public:

    GameState();
    GameState(int, int);
    GameState(int, int, bn::bg_palette_item const&);

    bn::regular_bg_ptr buildBG();
    bn::optional<bn::sprite_ptr> buildSprite(const bn::sprite_item &, int, int);
    const bn::bg_palette_item getCommonPalette();

    //void setCellTile(int);
    void setCellTile(int, int, int);

    bn::regular_bg_map_cell& retrieveCell(int, int);

    void resetMap();
    void refreshScreen(bn::regular_bg_map_ptr &);
    void scrollScreen(int, int, bn::regular_bg_ptr &);

    void PaperSheetPattern_Regular();
    void PaperSheetPattern_Holed();
    void PaperSheetPattern_Scrollable();
    void PaperSheetPattern_PuzzleSelection(int&, int&);

    //virtual int updateState() = 0;
    virtual void toggleStateVisibility(bool) = 0;
    virtual void toggleFadeEffect() = 0;

    virtual ~GameState();
};

#endif // STATE_BASE_H


code:
#ifndef STATE_FREE_PLAY_MENU_H
#define STATE_FREE_PLAY_MENU_H

#include "bn_sprite_animate_actions.h"
#include "bn_bg_palette_actions.h"
#include "bn_keypad.h"
#include "bn_string.h"
#include "bn_blending_actions.h"

#include "state_base.h"
#include "picross_solutions.h"
#include "tools.h"
#include "vn_text_output.h"

#include "bn_sprite_items_cursor_circle.h"
#include "bn_sprite_items_scribble_star.h"

class PuzzleSelect : public GameState
{
    bn::regular_bg_ptr bg;
    bn::regular_bg_map_ptr map;

    bn::array<int, 2> cursor_position = {15, 13};
    bn::optional<bn::sprite_ptr> cursor_sprite, scribble_left;
    bn::sprite_animate_action<2> two_frame_anim = bn::create_sprite_animate_action_forever
                        (*scribble_left, 11, bn::sprite_items::scribble_star.tiles_item(), 0,1);
    bn::array<bool, 5> slots_occupied = {0};

    int menu_hrz_lower_limit, menu_hrz_upper_limit,
        menu_vrt_lower_limit, menu_vrt_upper_limit;

    bn::vector<bn::sprite_ptr, 17> symbols;
    bn::sprite_text_generator* text_gnrtr;

    bool empty_selection = false;
    int frame_counter = 0;

public:
    PuzzleSelect(bn::sprite_text_generator*);
    void showMenu();
    void showMenuText();

    bn::array<bool, 144> const& getSelectedPuzzle();

    int updateState();

    void toggleStateVisibility(bool) override;
    void toggleFadeEffect() override;

    ~PuzzleSelect();
};

#endif // STATE_FREE_PLAY_MENU_H


code:
#ifndef STATE_MAIN_H
#define STATE_MAIN_H

#include "bn_audio.h"
#include "bn_bg_palette_actions.h"
#include "bn_sprite_animate_actions.h"
#include "bn_sprite_builder.h"
#include "bn_sram.h"

#include "picross_grid.h"
#include "picross_solutions.h"
#include "tools.h"
#include "state_base.h"
#include "vn_text_output.h"

#include "bn_sprite_items_cursor_pen.h"
#include "bn_sprite_items_notonochan.h"
#include "bn_sprite_items_scribble_heart.h"
#include "bn_sprite_items_scribble_star.h"
#include "bn_sprite_items_stamp.h"

class MainGame : public GameState
{
protected:
    bn::regular_bg_ptr bg;
    bn::regular_bg_map_ptr map;

    PicrossGrid grid;
    bn::optional<bn::sprite_ptr> cursor_sprite;
    bn::optional<bn::sprite_ptr> notono_window, scribble_right, stamp;
    bn::array<bn::sprite_animate_action<2>, 2> two_frame_anim =
    {
        bn::create_sprite_animate_action_forever
                    (*notono_window, 5, bn::sprite_items::notonochan.tiles_item(), 0,1),
        bn::create_sprite_animate_action_forever
                    (*scribble_right, 10, bn::sprite_items::scribble_heart.tiles_item(), 0,1)
    };

    bn::vector<bn::sprite_ptr, 15> symbols;
    bn::sprite_text_generator* text_gnrtr;

    //text _text;
    bool mistake_made, puzzle_solved;
    int frames2skip, offset, frame_counter;

    bool fading_out = false;
    int fade_counter = 0;

public:
    MainGame(bn::sprite_text_generator *);
    MainGame(bn::array<bool, 144> const &);

    bn::sprite_animate_action<2>& initAnimateActions(bn::sprite_ptr&, int);
    void redrawHints();

    void drawCreatorModeInstructions();

    void createPuzzle();
    void solvePuzzle(bn::array<bool, 144> const &);

    int updateState(bn::array<bool, 144> const &);
    int updateState();

    void toggleStateVisibility(bool) override;
    void toggleFadeEffect() override;

    ~MainGame();
};

#endif // STATE_MAIN_H


code:
#ifndef STATE_MAIN_TIMED_H
#define STATE_MAIN_TIMED_H

#include "state_main.h"
#include "bn_log.h"

class ArcadeGame : public MainGame
{
    int completion_time, time_limit, completion_time_delta,
        mistake_counter, crossed_square_counter, longest_coloring_time_delta;
    int one_second_frames;
public:
    ArcadeGame();
    ArcadeGame(int);
    int GradeCalculator();
    int updateState();
    ~ArcadeGame();
};

#endif // STATE_MAIN_TIMED_H


code:
#ifndef STATE_START_H
#define STATE_START_H

#include "bn_blending_actions.h"
#include "bn_blending_fade_alpha.h"
#include "bn_sprite_animate_actions.h"

#include "state_base.h"
#include "vn_text_output.h"

#include "bn_regular_bg_items_title.h"
#include "bn_sprite_items_logo_butano.h"
#include "bn_sprite_items_scribble_star.h"
#include "bn_sprite_items_cursor_pen.h"

class MainMenu : public GameState
{
    bn::regular_bg_ptr bg_pattern;
    bn::regular_bg_ptr bg_foreground;
    bn::regular_bg_map_ptr map;

    const int lower_bound = 4;
    const int upper_bound = 68;
    const int x_coord = 54;

    bn::array<int, 2> cursor_position = {x_coord, lower_bound};
    bn::optional<bn::sprite_ptr> cursor_sprite, logo;

    text* _text;

    int foreground_x = 222;

    const bn::string_view credits[7] =
    {
        "Press A to skip credit text, B to exit to main menu!",
        "Also, visit notabug.org/lv10groove/notenogram for details and source code/assets!",
        "Programming, inbuilt puzzles, art assets and sounds by kva64 (kva64.itch.io)",
        "Butano engine by GValiente (github.com/GValiente)",
        "BGM by congusbongus (soundcloud.com/congus-bongus, ModArchive ID 85757)",
        "Original GBA Jam 2022 logo designs (found at gbajam22.github.io) by foopod (foopod.itch.io) and exelotl (exelo.tl)",
        "This text will now be displayed from the beginning..."
    };

    int script_ptr,line_ptr,symbol_ptr;

public:
    int refresh_counter = 0;
    bool displaying_logo1, displaying_logo2, displaying_credits, returning_from_state;

    MainMenu(text*);
    void initScrollingBG();
    void displayIntro();
    void displayMainMenu();
    void displayCredits();

    int updateState();
    void toggleStateVisibility(const bool) override;
    void toggleFadeEffect() override;

    ~MainMenu();
};

#endif // STATE_START_H


code:
#ifndef STATE_STORY_H
#define STATE_STORY_H

#include "bn_keypad.h"
#include "state_base.h"
#include "vn_text_output.h"

#include "bn_regular_bg_items_end_nobisu.h"
#include "bn_regular_bg_items_end_notono.h"
#include "bn_regular_bg_items_end_nonogami.h"

class StoryMode : public GameState
{
    bn::regular_bg_ptr bg_pattern;
    bn::optional<bn::regular_bg_ptr> bg_foreground;
    bn::regular_bg_map_ptr map;

    int ending,script_ptr,symbol_ptr,line_ptr;
    bool showing_rank = false;

    text* _text;
public:
    StoryMode(bn::sprite_text_generator *stg);
    StoryMode(text *stg, bool);

    int drawIntroText();
    int drawEnd1Text();
    int drawEnd2Text();
    int drawEnd3Text();
    int drawRankText();

    void setTextOutputOptions(int);
    void setOptionalBG();
    void eraseOptionalBG();

    int updateState();

    void toggleStateVisibility(bool) override;
    void toggleFadeEffect() override;

    ~StoryMode();
};

#endif // STATE_STORY_H


code:
#ifndef STATE_TUTORIAL_H
#define STATE_TUTORIAL_H

#include "state_base.h"
#include "vn_text_output.h"
#include "bn_sprite_items_arrow_col.h"
#include "bn_sprite_items_arrow_row.h"
#include "bn_sprite_items_bar_horz.h"
#include "bn_sprite_items_good.h"
#include "bn_sprite_items_not_good.h"

class TutorialMode : public GameState
{
private:
    bn::regular_bg_ptr bg_pattern;
    bn::optional<bn::regular_bg_ptr> bg_foreground;
    bn::regular_bg_map_ptr map;

    bn::optional<bn::sprite_ptr> sprite;

    int script_ptr,symbol_ptr,line_ptr;

    const int map_redraw_start_x = 8;
    const int map_redraw_start_y = 9;
    const int map_redraw_width = 20;
    const int map_redraw_height = 16;

    const int text_redraw_start_y = 20;

    text* _text;

    bool bg_redrawn, sprites_redrawn;

    void initScreen();
    int drawText();

    void clearBG();

    void BasicRulesExample(bool,bool);
    void SeparatedSquaresExample(bool);
    void SeparatedSquaresOrderExample(bool, bool);

    void StrategyTipOne_Full();
    void StrategyTipOne_Empty();
    void StrategyTipOne_Group();
    void StrategyTipOne_Advanced();

    void StrategyTipTwo_Single(int);
    void StrategyTipTwo_Multiple(int);

    void StrategyTipThree();

public:
    TutorialMode();
    TutorialMode(bn::sprite_text_generator*);
    TutorialMode(text*);

    int updateState();

    void toggleStateVisibility(bool) override;
    void toggleFadeEffect() override;

    ~TutorialMode();
};

#endif // STATE_TUTORIAL_H


code:
#ifndef TOOLS_H
#define TOOLS_H

#include "bn_array.h"
#include "bn_fixed.h"
#include "bn_sram.h"
#include "bn_log.h"

namespace tool
{
    int cellX2Screen(int, int);
    int cellY2Screen(int, int);
    int cellX2Screen(bn::fixed, int);
    int cellY2Screen(bn::fixed, int);

    bool validateSRAMData(int);

    //write/read-only to avoid dangling references I guess
    void boolArray2UInt(bn::array<bool, 144> const &, int);
    void UInt2BoolArray(bn::array<bool, 144> &, int);
}

#endif // TOOLS_H


code:
#ifndef VN_TEXT_OUTPUT_H
#define VN_TEXT_OUTPUT_H

#include "bn_sprite_item.h"
#include "bn_sprite_ptr.h"

#include "bn_vector.h"
#include "bn_fixed_point.h"
#include "bn_string.h"
#include "bn_log.h"

#include "bn_sprite_text_generator.h"

#define TEXT_X -108
#define TEXT_Y -20
#define MAX_WIDTH 34
#define MAX_ROWS_8 10
#define MAX_ROWS_16 2

#define TEXT_NAME_X -111
#define TEXT_NAME_Y 28

class text
{
    bn::vector<bn::sprite_ptr, MAX_WIDTH> symbols;
    //this should store indexes for first and last symbols in every line of on-screen text
    //(retrieved once via outputMultipleLines for use in typewriter output)
    bn::vector<int, MAX_ROWS_8> line_starters;
    bn::vector<int, MAX_ROWS_8> line_breakers;
    int line_counter;

public:
    bn::sprite_text_generator* text_gnrtr;

    text();
    text(text*);
    text(bn::sprite_text_generator*);
    text(bn::string_view const&, bn::sprite_text_generator*);
    bool output_Typewriter(bn::string_view const &, int&, int&, int const&);
    bool output_Typewriter(bn::string_view const &, int&, int&, int const&, int const&);
    bool output_NoEffect(bn::string_view const &);

    void outputSingleLine(bn::string_view const &);
    void outputSingleLine(int y, bn::string_view const &);
    void outputSingleLine(int x, int y, bn::string_view const &);

    //object init for multiple line output moved to a separate method
    void initTextOutput(bn::string_view const&);
    //fills out index vectors for separating lines
    void breakIntoMultipleLines(bn::string_view const &);
    //coordinates for blinking cursor
    bn::fixed_point getLastSymbolCoords();

    void clear();
    //redefine all index vectors and line counter
    void redraw(bn::string_view const&);
    ~text();
};

#endif // VN_TEXT_OUTPUT_H


code:
zlib License

(C) 2020-2021 Gustavo Valiente (gustavo.valiente@prontonmail.com)

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.


code:
The MIT License

Copyright (c) 2015 Manuel Sánchez

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


code:
Copyright 2020 - 2021 DenSinH and fleroviux

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


code:
The MIT License (MIT)

Copyright (c) 2016 jwellbelove, https://github.com/ETLCPP/etl, http://www.etlcpp.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


code:
MIT License

Copyright (c) 2020 Rodrigo Alfonso

Permission is hereby granted, free of charge, to any person obtaining a
copy
of this software and associated documentation files (the "Software"), to
deal
in the Software without restriction, including without limitation the
rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE
SOFTWARE.


code:
Copyright 2019 João Baptista de Paula e Silva

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


code:
Copyright 2005-2009 J Vijn

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


code:
/****************************************************************************
 *                                                          __              *
 *                ____ ___  ____ __  ______ ___  ____  ____/ /              *
 *               / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __  /               *
 *              / / / / / / /_/ />  </ / / / / / /_/ / /_/ /                *
 *             /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/                 *
 *                                                                          *
 *               Nintendo DS & Gameboy Advance Sound System                 *
 *                                                                          *
 *         Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org)         *
 *                                                                          *
 * Permission to use, copy, modify, and/or distribute this software for any *
 * purpose with or without fee is hereby granted, provided that the above   *
 * copyright notice and this permission notice appear in all copies.        *
 *                                                                          *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF         *
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  *
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES   *
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN    *
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  *
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.           *
 ****************************************************************************/


code:
Copyright (c) 2011-2015, 2019-2020 Antonio Niño Díaz <antonio_nd@outlook.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


code:
#!/bin/python3
import os

if os.path.exists("notenogram.sav"):
	datasize = 18*3
	bitindex = 0
	savefile = open("notenogram.sav", "rb").read(datasize)
	datafile = open("notekeeper_output", "w")
	print("save found!")
	for i in range(3):
		while bitindex < datasize:
			puzzleindex = "constexpr bn::array<bool, 144> NotekeeperPuzzle_{}\n"
			datafile.write(puzzleindex.format(i))
			datafile.write("	{\n")
			for number in range(18):
				byterow = "		"
				byte = savefile[bitindex]
				for bit in range(8):
					bitstring = "{}, "
					if bit == 7:
						if number == 17:
							bitstring = "{}\n"
						else:
							bitstring += "\n"
					byterow += bitstring.format((byte >> bit) & 1)
				datafile.write(byterow)
				bitindex += 1
			datafile.write("	};\n\n")
	datafile.close()
	print("puzzles converted!")
else:
	print("save not found!")


code:
#include "fade_transparency_effects.h"

namespace fx
{
    bn::blending_transparency_alpha_loop_action logo_action(30, 1);

    void introLogoFade(int & frames)
    {
        if (frames < 30 || (frames >= 170 && frames < 200))
        {
            fx::logo_action.update();
        }
    }
    void simpleFade(int& frames, bool fading_out)
    {
        bn::blending_fade_alpha_loop_action fade_action(30, fading_out ? 0 : 1);
        while (++frames <= 30)
        {
            fade_action.update();
            bn::core::update();
        }
        frames = 0;
    }
    void hBlankFade(int& frames, bool fading_out)
    {
        /*int stripe_counter = 0;
        bn::array<bn::blending_fade_alpha, 160> fade_alphas;

        for (int i = 0; i < 160; ++i)
        {
            fade_alphas[i].set_value(fading_out ? 0 : 1);
        }

        bn::blending_fade_alpha_hbe_ptr fade_alphas_hbe =
                bn::blending_fade_alpha_hbe_ptr::create(fade_alphas);

        //bn::blending_fade_alpha_loop_action fade_action(60, !fading_out);
        while (frames <= 60)
        {
            for(int index = 0, amplitude = 160 / 2; index < amplitude; ++index)
            {
                bn::fixed fade_alpha = bn::fixed(index) / amplitude;
                fade_alphas[(160 / 2) + index].set_value(fade_alpha);
                fade_alphas[(160 / 2) - index - 1].set_value(fade_alpha);
            }

            bn::core::update();
        }*/
    }
}


code:
#include "game_loop.h"
namespace loop
{
    void solve_puzzle(bn::array<bool, 144> const& puzzle)
    {
        MainGame _actual_picross(puzzle);
        bn::core::update();
        while (_actual_picross.updateState(puzzle) != 0)
        {
            bn::core::update();
        }
    }

    int solve_arcade_puzzle()
    {
        ArcadeGame _story_picross;
        bn::core::update();
        int result = -1;
        while (result == -1)
        {
            result = _story_picross.updateState();
            bn::core::update();
        }
        return result;
    }

    void select_puzzle(bn::sprite_text_generator* _t)
    {
        PuzzleSelect _puzzle_select(_t);
        int option = 1;
        bn::core::update();
        while (option != 0)
        {
            option = _puzzle_select.updateState();
            if(option == 4)
            {
                _puzzle_select.toggleStateVisibility(false);
                solve_puzzle(_puzzle_select.getSelectedPuzzle());
                _puzzle_select.toggleStateVisibility(true);
            }
            bn::core::update();
        }
    }

    void make_puzzle(bn::sprite_text_generator* _t)
    {
        MainGame _actual_picross(_t);
        bn::core::update();
        while (_actual_picross.updateState() != 0)
        {
            bn::core::update();
        }
    }

    void init_tutorial_mode(bn::sprite_text_generator* _t)
    {
        TutorialMode _tutorial_mode(_t);
        bn::core::update();
        while (_tutorial_mode.updateState() != 0)
        {
            bn::core::update();
        }
    }

    void init_story_mode(bn::sprite_text_generator* _t)
    {
        StoryMode _story_mode(_t);
        bn::core::update();
        int option = 1;
        while (option != 0)
        {
            _story_mode.setOptionalBG();
            option = _story_mode.updateState();
            if(option == 4)
            {
                _story_mode.toggleStateVisibility(false);
                _story_mode.setTextOutputOptions(solve_arcade_puzzle());
                _story_mode.toggleStateVisibility(true);
            }
            bn::core::update();
        }
    }

    void menu()
    {
        bn::sprite_font font(
                bn::sprite_items::deadline_tracker_8x8, utf8_chars_map.reference(),
                character_widths);
        bn::sprite_text_generator txt(font);
        bn::sprite_text_generator* _txt = &txt;

        text* _t = new text(_txt);

        MainMenu _menu(_t);
        //bn::core::update();
        while (1)
        {
            bn::core::update();
            if (_menu.returning_from_state)
            {
                _menu.returning_from_state = false;
                _menu.toggleStateVisibility(true);
            }

            else if (_menu.displaying_logo1 || _menu.displaying_logo2)
            {
                fx::introLogoFade(_menu.refresh_counter);
            }

            switch(_menu.updateState())
                {
                case 1:
                    select_puzzle(_txt);
                    break;
                case 2:
                    make_puzzle(_txt);
                    break;
                case 3:
                    _menu.displaying_credits = true;
                    break;
                case 5:
                    init_story_mode(_txt);
                    break;
                case 6:
                    init_tutorial_mode(_txt);
                    break;
                default:
                    break;
                }
        }
    }
}


code:
#include "bn_core.h"
#include "bn_bg_palettes.h"
#include "bn_music_items.h"
#include "bn_sprite_actions.h"
#include "bn_vector.h"

#include "game_loop.h"

#define PLAY_MENU 1
#define CREATE 2
#define CREDITS 3
#define PLAY 4
#define STORY_MODE 5
#define TUTORIAL_MODE 6
#define GO_BACK 0
#define CONTINUE -1

int main()
{
    bn::core::init();

    bn::bg_palettes::set_transparent_color(bn::color(3, 3, 3));

    bn::music_items::mustard_loop.play(0.5);

    loop::menu();
}


code:
#include "picross_grid.h"

PicrossGrid::PicrossGrid()
{
    cursor_position[0] = (screen_cell_upper_limit + screen_cell_lower_limit)/2;
    cursor_position[1] = cursor_position[0];

    /*for (int i = 0; i < 18; ++i)
    {
        grid_[i] = 0x00;
        if (i < 6)
        {
            grid_hints_left.push_back(0);
            grid_hints_up.push_back(0);
        }
    }*/

    for (int i = 0; i < 12; ++i)
    {
        for (int j = 0; j < 12; ++j)
        {
            grid[12*i+j] = false;
            if (j < 6)
            {
                grid_hints_left.push_back(0);
                grid_hints_up.push_back(0);
            }
        }
    }
}

int PicrossGrid::getCursorX()
{
    return cursor_position[0];
}

int PicrossGrid::getCursorY()
{
    return cursor_position[1];
}

int PicrossGrid::getCurrentGridIndex()
{
    return cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit);
}

/*void PicrossGrid::markCell(int marking)
{
    tool::writeBit2Array(grid_, cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit), marking);
}

bool PicrossGrid::getCell(int index)
{
    return tool::retrieveBitFromArray(grid_, index);
}*/

bool PicrossGrid::processKeyInput(bn::regular_bg_map_cell& cell)
{
    bn::regular_bg_map_cell_info info(cell);
    if (bn::keypad::a_pressed())
    {
        int current_index = info.tile_index();
        int new_index = 1;
        if (current_index == 1 || current_index == 2)
        {
            new_index = 3;
            //markCell(1);
            grid[cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit)] = true;
            bn::sound_items::pen_color.play(1);
        }
        else
        {
            //markCell(0);
            grid[cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit)] = false;
        }
        info.set_tile_index(new_index);
        cell = info.cell();
        return true;
    }
    else if (bn::keypad::b_pressed())
    {
        int current_index = info.tile_index();
        int new_index = 1;
        if (current_index == 1 || current_index == 3)
        {
            new_index = 2;
            //markCell(0);
            grid[cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit)] = false;
            bn::sound_items::pen_cross.play(1);
        }
        info.set_tile_index(new_index);
        cell = info.cell();
        return true;
    }
    else return false;
}

bool PicrossGrid::processKeyContinuousInput(bn::regular_bg_map_cell& cell)
{
    bn::regular_bg_map_cell_info info(cell);
    if (bn::keypad::a_held())
    {
        int current_index = info.tile_index();
        if (current_index == 1)
        {
            //markCell(1);
            grid[cursor_position[0]-screen_cell_lower_limit+12*(cursor_position[1]-screen_cell_lower_limit)] = true;
            info.set_tile_index(3);
            cell = info.cell();
            bn::sound_items::pen_color.play(1);
        }
        return true;
    }
    else if (bn::keypad::b_held())
    {
        int current_index = info.tile_index();
        if (current_index == 1)
        {
            info.set_tile_index(2);
            cell = info.cell();
            bn::sound_items::pen_cross.play(1);
        }
        return true;
    }
    else return false;
}

bool PicrossGrid::processDPadInput()
{
    if (bn::keypad::down_pressed())
    {
        if (cursor_position[1] < screen_cell_upper_limit)
        {
            ++cursor_position[1];
        }
        return true;
    }
    else if (bn::keypad::up_pressed())
    {
        if (cursor_position[1] > screen_cell_lower_limit)
        {
            --cursor_position[1];
        }
        return true;
    }
    if (bn::keypad::right_pressed())
    {
        if (cursor_position[0] < screen_cell_upper_limit)
        {
            ++cursor_position[0];
        }
        return true;
    }
    else if (bn::keypad::left_pressed())
    {
        if (cursor_position[0] > screen_cell_lower_limit)
        {
            --cursor_position[0];
        }
        return true;
    }
    return false;
}

bool PicrossGrid::processDPadContinuousInput(int &frames2skip)
{
    if (bn::keypad::down_pressed() || (bn::keypad::down_held() && frames2skip == 10))
    {
        if (cursor_position[1] < screen_cell_upper_limit)
        {
            ++cursor_position[1];
            frames2skip = 0;
        }
        return true;
    }
    else if (bn::keypad::up_pressed() || (bn::keypad::up_held() && frames2skip == 10))
    {
        if (cursor_position[1] > screen_cell_lower_limit)
        {
            --cursor_position[1];
            frames2skip = 0;
        }
        return true;
    }
    if (bn::keypad::left_pressed() || (bn::keypad::left_held() && frames2skip == 10))
        {
            if (cursor_position[0] > screen_cell_lower_limit)
            {
                --cursor_position[0];
                frames2skip = 0;
            }
            return true;
        }
    else if (bn::keypad::right_pressed() || (bn::keypad::right_held() && frames2skip == 10))
    {
        if (cursor_position[0] < screen_cell_upper_limit)
        {
            ++cursor_position[0];
            frames2skip = 0;
        }
        return true;
    }
    ++frames2skip;
    return false;
}

//for on-screen hints, true if wrong cell is marked
/*bool PicrossGrid::checkCurrentCell(bn::array<char, 18> const &solution)
{

    return tool::retrieveBitFromArray(grid_, 12*(cursor_position[1]-screen_cell_lower_limit)
            +(cursor_position[0]-screen_cell_lower_limit)) !=
           tool::retrieveBitFromArray(solution, 12*(cursor_position[1]-screen_cell_lower_limit)
            +(cursor_position[0]-screen_cell_lower_limit));
}*/
bool PicrossGrid::checkCurrentCell(bn::array<bool, 144> const &solution)
{
    return
            grid[12*(cursor_position[1]-screen_cell_lower_limit)
                +(cursor_position[0]-screen_cell_lower_limit)] &&
            !solution[12*(cursor_position[1]-screen_cell_lower_limit)
                +(cursor_position[0]-screen_cell_lower_limit)];
}

//for solution overall, true if 100% correct
/*bool PicrossGrid::checkSolution(bn::array<char, 18> const &solution)
{
    for (int i = 0; i < 18; ++i)
    {
        if (grid_[i] != solution[i]) return false;
    }
    return true;
}*/
bool PicrossGrid::checkSolution(bn::array<bool, 144> const &solution)
{
    for (int i = 0; i < 144; ++i)
    {
        if (grid[i] != solution[i]) return false;
    }
    return true;
}

/*bn::array<char, 18> const &PicrossGrid::getCurrentGrid()
{
    return grid_;
}*/
bn::array<bool, 144> const &PicrossGrid::getCurrentGrid()
{
    return grid;
}
//redrawing number hints on screen
/*void PicrossGrid::updateHints(bn::array<char, 18> const &this_grid)
{
    grid_hints_left.clear();
        grid_hints_up.clear();

        //check every row of 12 squares
        for (int i = 0; i < 12; ++i)
        {
            int row_cell_counter = 0;
            int col_cell_counter = 0;

            int hint_counter_up = 0;
            int hint_counter_left = 0;
            //and every column too for faster execution
            for (int j = 11; j >= 0; --j)
            {
                //this checks for bits in the char array 144*4 times, but i'm sure there's a faster way to do that
                if (tool::retrieveBitFromArray(this_grid, 12*j+i)) ++col_cell_counter;
                if (!tool::retrieveBitFromArray(this_grid, 12*j+i) || j == 0)
                {
                    if (col_cell_counter > 0)
                    {
                        grid_hints_up.push_back(col_cell_counter);
                        ++hint_counter_up;
                        col_cell_counter = 0;
                    }
                }
                if (tool::retrieveBitFromArray(this_grid, 12*i+j)) ++row_cell_counter;
                if (!tool::retrieveBitFromArray(this_grid, 12*i+j) || j == 0)
                {
                    if (row_cell_counter > 0)
                    {
                        grid_hints_left.push_back(row_cell_counter);
                        ++hint_counter_left;
                        row_cell_counter = 0;
                    }
                }
            }

            for (int j = 0; j < 6 - hint_counter_left; ++j)
            {
                grid_hints_left.push_back(0);
            }
            for (int j = 0; j < 6 - hint_counter_up; ++j)
            {
                grid_hints_up.push_back(0);
            }
        }
}*/

void PicrossGrid::updateHints(bn::array<bool, 144> const &_grid)
{
    grid_hints_left.clear();
        grid_hints_up.clear();

        //check every row of 12 squares
        for (int i = 0; i < 12; ++i)
        {
            int row_cell_counter = 0;
            int col_cell_counter = 0;

            //how many numbers to push into hint vectors in one iteration
            int hint_counter_up = 0;
            int hint_counter_left = 0;
            //and check every column too for faster execution
            for (int j = 11; j >= 0; --j)
            {
                if (_grid[12*j+i]) ++col_cell_counter;
                if (!_grid[12*j+i] || j == 0)
                {
                    if (col_cell_counter > 0)
                    {
                        grid_hints_up.push_back(col_cell_counter);
                        ++hint_counter_up;
                        col_cell_counter = 0;
                    }
                }
                if (_grid[12*i+j]) ++row_cell_counter;
                if (!_grid[12*i+j] || j == 0)
                {
                    if (row_cell_counter > 0)
                    {
                        grid_hints_left.push_back(row_cell_counter);
                        ++hint_counter_left;
                        row_cell_counter = 0;
                    }
                }
            }

            for (int j = 0; j < 6 - hint_counter_left; ++j)
            {
                grid_hints_left.push_back(0);
            }
            for (int j = 0; j < 6 - hint_counter_up; ++j)
            {
                grid_hints_up.push_back(0);
            }
        }
}

void PicrossGrid::create()
{
    creator_mode = true;
}

void PicrossGrid::solve()
{
    creator_mode = false;
}

void PicrossGrid::resetGrid()
{
    grid_hints_left.clear();
    grid_hints_up.clear();

    /*for (int i = 0; i < 18; ++i)
    {
        grid_[i] = 0;
    }*/

    for (int i = 0; i < 144; ++i)
    {
        grid[i] = false;
    }
}

PicrossGrid::~PicrossGrid()
{
    grid_hints_left.clear();
    grid_hints_up.clear();
}


code:
#include "picross_solutions.h"

namespace puzzle
{

}