Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,25 @@
#include "audio.h"
#include <stdbool.h>
struct kinc_a1_channel {
kinc_a1_sound_t *sound;
float position;
bool loop;
volatile float volume;
float pitch;
};
struct kinc_a1_stream_channel {
kinc_a1_sound_stream_t *stream;
int position;
};
struct kinc_internal_video_channel {
struct kinc_internal_video_sound_stream *stream;
int position;
};
#include "audio.c.h"
#include "sound.c.h"
#include "soundstream.c.h"

View File

@ -0,0 +1,253 @@
#include "audio.h"
#include <stdint.h>
#include <kinc/audio2/audio.h>
#include <kinc/math/core.h>
#include <kinc/threads/atomic.h>
#include <kinc/threads/mutex.h>
#include <kinc/video.h>
#include <assert.h>
#include <stdlib.h>
static kinc_mutex_t mutex;
#define CHANNEL_COUNT 16
static kinc_a1_channel_t channels[CHANNEL_COUNT];
static kinc_a1_stream_channel_t streamchannels[CHANNEL_COUNT];
static kinc_internal_video_channel_t videos[CHANNEL_COUNT];
static float sampleLinear(int16_t *data, float position) {
int pos1 = (int)position;
int pos2 = (int)(position + 1);
float sample1 = data[pos1] / 32767.0f;
float sample2 = data[pos2] / 32767.0f;
float a = position - pos1;
return sample1 * (1 - a) + sample2 * a;
}
static void kinc_a2_on_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) {
kinc_a1_mix(buffer, samples);
}
/*float sampleHermite4pt3oX(s16* data, float position) {
float s0 = data[(int)(position - 1)] / 32767.0f;
float s1 = data[(int)(position + 0)] / 32767.0f;
float s2 = data[(int)(position + 1)] / 32767.0f;
float s3 = data[(int)(position + 2)] / 32767.0f;
float x = position - (int)(position);
// 4-point, 3rd-order Hermite (x-form)
float c0 = s1;
float c1 = 0.5f * (s2 - s0);
float c2 = s0 - 2.5f * s1 + 2 * s2 - 0.5f * s3;
float c3 = 0.5f * (s3 - s0) + 1.5f * (s1 - s2);
return ((c3 * x + c2) * x + c1) * x + c0;
}*/
void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples) {
for (uint32_t i = 0; i < samples; ++i) {
float left_value = 0.0f;
float right_value = 0.0f;
#if 0
__m128 sseSamples[4];
for (int i = 0; i < channelCount; i += 4) {
s16 data[4];
for (int i2 = 0; i2 < 4; ++i2) {
if (channels[i + i2].sound != nullptr) {
data[i2] = *(s16*)&channels[i + i2].sound->data[channels[i + i2].position];
channels[i + i2].position += 2;
if (channels[i + i2].position >= channels[i + i2].sound->size) channels[i + i2].sound = nullptr;
}
else {
data[i2] = 0;
}
}
sseSamples[i / 4] = _mm_set_ps(data[3] / 32767.0f, data[2] / 32767.0f, data[1] / 32767.0f, data[0] / 32767.0f);
}
__m128 a = _mm_add_ps(sseSamples[0], sseSamples[1]);
__m128 b = _mm_add_ps(sseSamples[2], sseSamples[3]);
__m128 c = _mm_add_ps(a, b);
value = c.m128_f32[0] + c.m128_f32[1] + c.m128_f32[2] + c.m128_f32[3];
value = max(min(value, 1.0f), -1.0f);
#else
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (channels[i].sound != NULL) {
left_value += sampleLinear(channels[i].sound->left, channels[i].position) * channels[i].volume * channels[i].sound->volume;
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
right_value += sampleLinear(channels[i].sound->right, channels[i].position) * channels[i].volume * channels[i].sound->volume;
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
channels[i].position += channels[i].pitch / channels[i].sound->sample_rate_pos;
// channels[i].position += 2;
if (channels[i].position + 1 >= channels[i].sound->size) {
if (channels[i].loop) {
channels[i].position = 0;
}
else {
channels[i].sound = NULL;
}
}
}
}
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (streamchannels[i].stream != NULL) {
float *samples = kinc_a1_sound_stream_next_frame(streamchannels[i].stream);
left_value += samples[0] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
right_value += samples[1] * kinc_a1_sound_stream_volume(streamchannels[i].stream);
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
if (kinc_a1_sound_stream_ended(streamchannels[i].stream)) {
streamchannels[i].stream = NULL;
}
}
}
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (videos[i].stream != NULL) {
float *samples = kinc_internal_video_sound_stream_next_frame(videos[i].stream);
left_value += samples[0];
left_value = kinc_max(kinc_min(left_value, 1.0f), -1.0f);
right_value += samples[1];
right_value = kinc_max(kinc_min(right_value, 1.0f), -1.0f);
if (kinc_internal_video_sound_stream_ended(videos[i].stream)) {
videos[i].stream = NULL;
}
}
}
kinc_mutex_unlock(&mutex);
#endif
assert(buffer->channel_count >= 2);
buffer->channels[0][buffer->write_location] = left_value;
buffer->channels[1][buffer->write_location] = right_value;
buffer->write_location += 1;
if (buffer->write_location >= buffer->data_size) {
buffer->write_location = 0;
}
}
}
void kinc_a1_init(void) {
for (int i = 0; i < CHANNEL_COUNT; ++i) {
channels[i].sound = NULL;
channels[i].position = 0;
}
for (int i = 0; i < CHANNEL_COUNT; ++i) {
streamchannels[i].stream = NULL;
streamchannels[i].position = 0;
}
kinc_mutex_init(&mutex);
kinc_a2_init();
kinc_a2_set_callback(kinc_a2_on_a1_mix, NULL);
}
kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique) {
kinc_a1_channel_t *channel = NULL;
kinc_mutex_lock(&mutex);
bool found = false;
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (channels[i].sound == sound) {
found = true;
break;
}
}
if (!found || !unique) {
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (channels[i].sound == NULL) {
channels[i].sound = sound;
channels[i].position = 0;
channels[i].loop = loop;
channels[i].pitch = pitch;
channels[i].volume = sound->volume;
channel = &channels[i];
break;
}
}
}
kinc_mutex_unlock(&mutex);
return channel;
}
void kinc_a1_stop_sound(kinc_a1_sound_t *sound) {
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (channels[i].sound == sound) {
channels[i].sound = NULL;
channels[i].position = 0;
break;
}
}
kinc_mutex_unlock(&mutex);
}
void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream) {
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (streamchannels[i].stream == stream) {
streamchannels[i].stream = NULL;
streamchannels[i].position = 0;
break;
}
}
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (streamchannels[i].stream == NULL) {
streamchannels[i].stream = stream;
streamchannels[i].position = 0;
break;
}
}
kinc_mutex_unlock(&mutex);
}
void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream) {
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (streamchannels[i].stream == stream) {
streamchannels[i].stream = NULL;
streamchannels[i].position = 0;
break;
}
}
kinc_mutex_unlock(&mutex);
}
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (videos[i].stream == NULL) {
videos[i].stream = stream;
videos[i].position = 0;
break;
}
}
kinc_mutex_unlock(&mutex);
}
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream) {
kinc_mutex_lock(&mutex);
for (int i = 0; i < CHANNEL_COUNT; ++i) {
if (videos[i].stream == stream) {
videos[i].stream = NULL;
videos[i].position = 0;
break;
}
}
kinc_mutex_unlock(&mutex);
}
float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel) {
return channel->volume;
}
void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume) {
KINC_ATOMIC_EXCHANGE_FLOAT(&channel->volume, volume);
}

View File

@ -0,0 +1,95 @@
#pragma once
#include <kinc/global.h>
#include "sound.h"
#include "soundstream.h"
#include <stdbool.h>
/*! \file audio.h
\brief Audio1 is a high-level audio-API that lets you directly play audio-files. Depending on the target-system it either sits directly on a high-level
system audio-API or is implemented based on Audio2.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_internal_video_sound_stream;
struct kinc_a1_channel;
typedef struct kinc_a1_channel kinc_a1_channel_t;
struct kinc_a1_stream_channel;
typedef struct kinc_a1_stream_channel kinc_a1_stream_channel_t;
struct kinc_internal_video_channel;
typedef struct kinc_internal_video_channel kinc_internal_video_channel_t;
/// <summary>
/// Initialize the Audio1-API.
/// </summary>
KINC_FUNC void kinc_a1_init(void);
/// <summary>
/// Plays a sound immediately.
/// </summary>
/// <param name="sound">The sound to play</param>
/// <param name="loop">Whether or not to automatically loop the sound</param>
/// <param name="pitch">Changes the pitch by providing a value that's not 1.0f</param>
/// <param name="unique">Makes sure that a sound is not played more than once at the same time</param>
/// <returns>A channel object that can be used to control the playing sound. Please be aware that NULL is returned when the maximum number of simultaneously
/// played channels was reached.</returns>
KINC_FUNC kinc_a1_channel_t *kinc_a1_play_sound(kinc_a1_sound_t *sound, bool loop, float pitch, bool unique);
/// <summary>
/// Stops the sound from playing.
/// </summary>
/// <param name="sound">The sound to stop</param>
KINC_FUNC void kinc_a1_stop_sound(kinc_a1_sound_t *sound);
/// <summary>
/// Starts playing a sound-stream.
/// </summary>
/// <param name="stream">The stream to play</param>
KINC_FUNC void kinc_a1_play_sound_stream(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Stops a sound-stream from playing.
/// </summary>
/// <param name="stream">The stream to stop.</param>
KINC_FUNC void kinc_a1_stop_sound_stream(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Gets the current volume of a channel. Only works correctly if the channel is still playing.
/// </summary>
/// <param name="channel">The channel to get the volume from</param>
/// <returns>The volume</returns>
KINC_FUNC float kinc_a1_channel_get_volume(kinc_a1_channel_t *channel);
/// <summary>
/// Sets the current volume of a channel. Only works correctly if the channel is still playing.
/// </summary>
/// <param name="channel">The channel to set the volume for</param>
/// <param name="volume">The volume to set</param>
/// <returns></returns>
KINC_FUNC void kinc_a1_channel_set_volume(kinc_a1_channel_t *channel, float volume);
/// <summary>
/// Mixes audio into the provided buffer. kinc_a1_init sets this as the callback for a2
/// but you can also call it manually to mix a1-audio with your own audio. To do that,
/// first call kinc_a1_init, then call kinc_a2_set_callback to set it to your own callback
/// and call kinc_a1_mix from within that callback. Please be aware that the callback
/// will run in a separate audio-thread.
/// </summary>
/// <param name="buffer">The audio-buffer to be filled</param>
/// <param name="samples">The number of samples to be filled in</param>
KINC_FUNC void kinc_a1_mix(kinc_a2_buffer_t *buffer, uint32_t samples);
void kinc_internal_play_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
void kinc_internal_stop_video_sound_stream(struct kinc_internal_video_sound_stream *stream);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,224 @@
#include "sound.h"
#define STB_VORBIS_HEADER_ONLY
#include <kinc/libs/stb_vorbis.c>
#include <kinc/audio2/audio.h>
#include <kinc/error.h>
#include <kinc/io/filereader.h>
#include <assert.h>
#include <string.h>
struct WaveData {
uint16_t audioFormat;
uint16_t numChannels;
uint32_t sampleRate;
uint32_t bytesPerSecond;
uint16_t bitsPerSample;
uint32_t dataSize;
uint8_t *data;
};
static void checkFOURCC(uint8_t **data, const char *fourcc) {
for (int i = 0; i < 4; ++i) {
kinc_affirm(**data == fourcc[i]);
++*data;
}
}
static void readFOURCC(uint8_t **data, char *fourcc) {
for (int i = 0; i < 4; ++i) {
fourcc[i] = **data;
++*data;
}
fourcc[4] = 0;
}
static void readChunk(uint8_t **data, struct WaveData *wave) {
char fourcc[5];
readFOURCC(data, fourcc);
uint32_t chunksize = kinc_read_u32le(*data);
*data += 4;
if (strcmp(fourcc, "fmt ") == 0) {
wave->audioFormat = kinc_read_u16le(*data + 0);
wave->numChannels = kinc_read_u16le(*data + 2);
wave->sampleRate = kinc_read_u32le(*data + 4);
wave->bytesPerSecond = kinc_read_u32le(*data + 8);
wave->bitsPerSample = kinc_read_u16le(*data + 14);
*data += chunksize;
}
else if (strcmp(fourcc, "data") == 0) {
wave->dataSize = chunksize;
wave->data = (uint8_t *)malloc(chunksize * sizeof(uint8_t));
kinc_affirm(wave->data != NULL);
memcpy(wave->data, *data, chunksize);
*data += chunksize;
}
else {
*data += chunksize;
}
}
static int16_t convert8to16(uint8_t sample) {
return (sample - 127) << 8;
}
static void splitStereo8(uint8_t *data, int size, int16_t *left, int16_t *right) {
for (int i = 0; i < size; ++i) {
left[i] = convert8to16(data[i * 2 + 0]);
right[i] = convert8to16(data[i * 2 + 1]);
}
}
static void splitStereo16(int16_t *data, int size, int16_t *left, int16_t *right) {
for (int i = 0; i < size; ++i) {
left[i] = data[i * 2 + 0];
right[i] = data[i * 2 + 1];
}
}
static void splitMono8(uint8_t *data, int size, int16_t *left, int16_t *right) {
for (int i = 0; i < size; ++i) {
left[i] = convert8to16(data[i]);
right[i] = convert8to16(data[i]);
}
}
static void splitMono16(int16_t *data, int size, int16_t *left, int16_t *right) {
for (int i = 0; i < size; ++i) {
left[i] = data[i];
right[i] = data[i];
}
}
#define MAXIMUM_SOUNDS 4096
static kinc_a1_sound_t sounds[MAXIMUM_SOUNDS] = {0};
static kinc_a1_sound_t *find_sound(void) {
for (int i = 0; i < MAXIMUM_SOUNDS; ++i) {
if (!sounds[i].in_use) {
return &sounds[i];
}
}
return NULL;
}
kinc_a1_sound_t *kinc_a1_sound_create(const char *filename) {
kinc_a1_sound_t *sound = find_sound();
assert(sound != NULL);
sound->in_use = true;
sound->volume = 1.0f;
sound->size = 0;
sound->left = NULL;
sound->right = NULL;
size_t filenameLength = strlen(filename);
uint8_t *data = NULL;
if (strncmp(&filename[filenameLength - 4], ".ogg", 4) == 0) {
kinc_file_reader_t file;
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
sound->in_use = false;
return NULL;
}
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
kinc_file_reader_close(&file);
int channels, sample_rate;
int samples = stb_vorbis_decode_memory(filedata, (int)kinc_file_reader_size(&file), &channels, &sample_rate, (short **)&data);
sound->channel_count = (uint8_t)channels;
sound->samples_per_second = (uint32_t)sample_rate;
sound->size = samples * 2 * sound->channel_count;
sound->bits_per_sample = 16;
free(filedata);
}
else if (strncmp(&filename[filenameLength - 4], ".wav", 4) == 0) {
struct WaveData wave = {0};
{
kinc_file_reader_t file;
if (!kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET)) {
sound->in_use = false;
return NULL;
}
uint8_t *filedata = (uint8_t *)malloc(kinc_file_reader_size(&file));
kinc_file_reader_read(&file, filedata, kinc_file_reader_size(&file));
kinc_file_reader_close(&file);
uint8_t *data = filedata;
checkFOURCC(&data, "RIFF");
uint32_t filesize = kinc_read_u32le(data);
data += 4;
checkFOURCC(&data, "WAVE");
while (data + 8 - filedata < (intptr_t)filesize) {
readChunk(&data, &wave);
}
free(filedata);
}
sound->bits_per_sample = (uint8_t)wave.bitsPerSample;
sound->channel_count = (uint8_t)wave.numChannels;
sound->samples_per_second = wave.sampleRate;
data = wave.data;
sound->size = wave.dataSize;
}
else {
assert(false);
}
if (sound->channel_count == 1) {
if (sound->bits_per_sample == 8) {
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
splitMono8(data, sound->size, sound->left, sound->right);
}
else if (sound->bits_per_sample == 16) {
sound->size /= 2;
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
splitMono16((int16_t *)data, sound->size, sound->left, sound->right);
}
else {
kinc_affirm(false);
}
}
else {
// Left and right channel are in s16 audio stream, alternating.
if (sound->bits_per_sample == 8) {
sound->size /= 2;
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
splitStereo8(data, sound->size, sound->left, sound->right);
}
else if (sound->bits_per_sample == 16) {
sound->size /= 4;
sound->left = (int16_t *)malloc(sound->size * sizeof(int16_t));
sound->right = (int16_t *)malloc(sound->size * sizeof(int16_t));
splitStereo16((int16_t *)data, sound->size, sound->left, sound->right);
}
else {
kinc_affirm(false);
}
}
sound->sample_rate_pos = 44100 / (float)sound->samples_per_second;
free(data);
return sound;
}
void kinc_a1_sound_destroy(kinc_a1_sound_t *sound) {
free(sound->left);
free(sound->right);
sound->left = NULL;
sound->right = NULL;
sound->in_use = false;
}
float kinc_a1_sound_volume(kinc_a1_sound_t *sound) {
return sound->volume;
}
void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value) {
sound->volume = value;
}

View File

@ -0,0 +1,58 @@
#pragma once
#include <kinc/global.h>
#include <kinc/audio2/audio.h>
#include <stdint.h>
/*! \file sound.h
\brief Sounds are pre-decoded on load and therefore primarily useful for playing sound-effects.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_a1_sound {
uint8_t channel_count;
uint8_t bits_per_sample;
uint32_t samples_per_second;
int16_t *left;
int16_t *right;
int size;
float sample_rate_pos;
float volume;
bool in_use;
} kinc_a1_sound_t;
/// <summary>
/// Create a sound from a wav file.
/// </summary>
/// <param name="filename">Path to a wav file</param>
/// <returns>The newly created sound</returns>
KINC_FUNC kinc_a1_sound_t *kinc_a1_sound_create(const char *filename);
/// <summary>
/// Destroy a sound.
/// </summary>
/// <param name="sound">The sound to destroy.</param>
KINC_FUNC void kinc_a1_sound_destroy(kinc_a1_sound_t *sound);
/// <summary>
/// Gets the current volume-multiplicator that's used when playing the sound.
/// </summary>
/// <param name="sound">The sound to query</param>
/// <returns>The volume-multiplicator</returns>
KINC_FUNC float kinc_a1_sound_volume(kinc_a1_sound_t *sound);
/// <summary>
/// Sets the volume-multiplicator that's used when playing the sound.
/// </summary>
/// <param name="sound">The sound to modify</param>
/// <param name="value">The volume-multiplicator to set</param>
KINC_FUNC void kinc_a1_sound_set_volume(kinc_a1_sound_t *sound, float value);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,128 @@
#include "soundstream.h"
#define STB_VORBIS_HEADER_ONLY
#include <kinc/libs/stb_vorbis.c>
#include <kinc/io/filereader.h>
#include <stdlib.h>
#include <string.h>
static kinc_a1_sound_stream_t streams[256];
static int nextStream = 0;
static uint8_t buffer[1024 * 10];
static int bufferIndex;
kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping) {
kinc_a1_sound_stream_t *stream = &streams[nextStream];
stream->myLooping = looping;
stream->myVolume = 1;
stream->rateDecodedHack = false;
stream->end = false;
kinc_file_reader_t file;
kinc_file_reader_open(&file, filename, KINC_FILE_TYPE_ASSET);
stream->buffer = &buffer[bufferIndex];
bufferIndex += (int)kinc_file_reader_size(&file);
uint8_t *filecontent = (uint8_t *)malloc(kinc_file_reader_size(&file));
kinc_file_reader_read(&file, filecontent, kinc_file_reader_size(&file));
kinc_file_reader_close(&file);
memcpy(stream->buffer, filecontent, kinc_file_reader_size(&file));
free(filecontent);
stream->vorbis = stb_vorbis_open_memory(buffer, (int)kinc_file_reader_size(&file), NULL, NULL);
if (stream->vorbis != NULL) {
stb_vorbis_info info = stb_vorbis_get_info(stream->vorbis);
stream->chans = info.channels;
stream->rate = info.sample_rate;
}
else {
stream->chans = 2;
stream->rate = 22050;
}
++nextStream;
return stream;
}
int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream) {
return stream->chans;
}
int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream) {
return stream->rate;
}
bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream) {
return stream->myLooping;
}
void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop) {
stream->myLooping = loop;
}
float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream) {
return stream->myVolume;
}
void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value) {
stream->myVolume = value;
}
bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream) {
return stream->end;
}
float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream) {
if (stream->vorbis == NULL)
return 0;
return stb_vorbis_stream_length_in_seconds(stream->vorbis);
}
float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream) {
if (stream->vorbis == NULL)
return 0;
return stb_vorbis_get_sample_offset(stream->vorbis) / stb_vorbis_stream_length_in_samples(stream->vorbis) * kinc_a1_sound_stream_length(stream);
}
void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream) {
if (stream->vorbis != NULL)
stb_vorbis_seek_start(stream->vorbis);
stream->end = false;
stream->rateDecodedHack = false;
}
float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream) {
if (stream->vorbis == NULL) {
for (int i = 0; i < stream->chans; ++i) {
stream->samples[i] = 0;
}
return stream->samples;
}
if (stream->rate == 22050) {
if (stream->rateDecodedHack) {
stream->rateDecodedHack = false;
return stream->samples;
}
}
float left, right;
float *samples_array[2] = {&left, &right};
int read = stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
if (read == 0) {
if (kinc_a1_sound_stream_looping(stream)) {
stb_vorbis_seek_start(stream->vorbis);
stb_vorbis_get_samples_float(stream->vorbis, stream->chans, samples_array, 1);
}
else {
stream->end = true;
for (int i = 0; i < stream->chans; ++i) {
stream->samples[i] = 0;
}
return stream->samples;
}
}
stream->samples[0] = samples_array[0][0];
stream->samples[1] = samples_array[1][0];
stream->rateDecodedHack = true;
return stream->samples;
}

View File

@ -0,0 +1,116 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
#include <stdint.h>
/*! \file soundstream.h
\brief Sound-Streams are decoded while playing and as such are useful for large audio-files like music or speech.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct stb_vorbis;
typedef struct kinc_a1_sound_stream {
struct stb_vorbis *vorbis;
int chans;
int rate;
bool myLooping;
float myVolume;
bool rateDecodedHack;
bool end;
float samples[2];
uint8_t *buffer;
} kinc_a1_sound_stream_t;
/// <summary>
/// Create a sound-stream from a wav file.
/// </summary>
/// <param name="filename">A path to a wav file</param>
/// <param name="looping">Defines whether the stream will be looped automatically</param>
/// <returns>The newly created sound-stream</returns>
KINC_FUNC kinc_a1_sound_stream_t *kinc_a1_sound_stream_create(const char *filename, bool looping);
/// <summary>
/// Gets the next audio-frame in the stream.
/// </summary>
/// <param name="stream">The stream to extract the frame from</param>
/// <returns>The next sample</returns>
KINC_FUNC float *kinc_a1_sound_stream_next_frame(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Gets the number of audio-channels the stream uses.
/// </summary>
/// <param name="stream">The stream to extract the number of channels from</param>
/// <returns>The number of audio-channels</returns>
KINC_FUNC int kinc_a1_sound_stream_channels(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Gets the sample-rate used by the stream.
/// </summary>
/// <param name="stream">The stream to extract the sample-rate from</param>
/// <returns>The sample-rate of the stream</returns>
KINC_FUNC int kinc_a1_sound_stream_sample_rate(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Returns whether the stream loops automatically.
/// </summary>
/// <param name="stream">The stream to extract the looping-information from</param>
/// <returns>Whether the stream loops</returns>
KINC_FUNC bool kinc_a1_sound_stream_looping(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Changes whether the stream is looped automatically.
/// </summary>
/// <param name="stream">The stream to change</param>
/// <param name="loop">The new loop value to set</param>
KINC_FUNC void kinc_a1_sound_stream_set_looping(kinc_a1_sound_stream_t *stream, bool loop);
/// <summary>
/// Returns whether the stream finished playing.
/// </summary>
/// <param name="stream">The stream to query</param>
/// <returns>Whether the stream finished playing</returns>
KINC_FUNC bool kinc_a1_sound_stream_ended(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Returns the length of the stream.
/// </summary>
/// <param name="stream">The stream to query</param>
/// <returns>The length of the stream in seconds</returns>
KINC_FUNC float kinc_a1_sound_stream_length(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Returns the current playing-position of the stream.
/// </summary>
/// <param name="stream">The stream to query</param>
/// <returns>The current playing-position in seconds</returns>
KINC_FUNC float kinc_a1_sound_stream_position(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Resets the stream to its start-position.
/// </summary>
/// <param name="stream">The stream to change</param>
KINC_FUNC void kinc_a1_sound_stream_reset(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Gets the stream's volume-multiplicator.
/// </summary>
/// <param name="stream">The stream to query</param>
/// <returns>The volume-multiplicator</returns>
KINC_FUNC float kinc_a1_sound_stream_volume(kinc_a1_sound_stream_t *stream);
/// <summary>
/// Sets the stream's volume-multiplicator.
/// </summary>
/// <param name="stream">The stream to change</param>
/// <param name="value">The volume-multiplicator</param>
KINC_FUNC void kinc_a1_sound_stream_set_volume(kinc_a1_sound_stream_t *stream, float value);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,3 @@
#define KINC_IMPLEMENTATION_AUDIO2
#include "audio.h"

View File

@ -0,0 +1,123 @@
#pragma once
#include <kinc/global.h>
#include <stdint.h>
/*! \file audio.h
\brief Audio2 is a low-level audio-API that allows you to directly provide a stream of audio-samples.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_A2_MAX_CHANNELS 8
typedef struct kinc_a2_buffer {
uint8_t channel_count;
float *channels[KINC_A2_MAX_CHANNELS];
uint32_t data_size;
uint32_t read_location;
uint32_t write_location;
} kinc_a2_buffer_t;
/// <summary>
/// Initializes the Audio2-API.
/// </summary>
KINC_FUNC void kinc_a2_init(void);
/// <summary>
/// Sets the callback that's used to provide audio-samples. This is the primary method of operation for Audio2. The callback is expected to write the requested
/// number of samples into the ring-buffer. The callback is typically called from the system's audio-thread to minimize audio-latency.
/// </summary>
/// <param name="kinc_a2_audio_callback">The callback to set</param>
/// <param name="userdata">The user data provided to the callback</param>
KINC_FUNC void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata), void *userdata);
/// <summary>
/// The current sample-rate of the system.
/// </summary>
KINC_FUNC uint32_t kinc_a2_samples_per_second(void);
/// <summary>
/// Sets a callback that's called when the system's sample-rate changes.
/// </summary>
/// <param name="kinc_a2_sample_rate_callback">The callback to set</param>
/// <param name="userdata">The user data provided to the callback</param>
/// <returns></returns>
KINC_FUNC void kinc_a2_set_sample_rate_callback(void (*kinc_a2_sample_rate_callback)(void *userdata), void *userdata);
/// <summary>
/// kinc_a2_update should be called every frame. It is required by some systems to pump their audio-loops but on most systems it is a no-op.
/// </summary>
KINC_FUNC void kinc_a2_update(void);
/// <summary>
/// Shuts down the Audio2-API.
/// </summary>
KINC_FUNC void kinc_a2_shutdown(void);
void kinc_a2_internal_init(void);
bool kinc_a2_internal_callback(kinc_a2_buffer_t *buffer, int samples);
void kinc_a2_internal_sample_rate_callback(void);
#ifdef KINC_IMPLEMENTATION_AUDIO2
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <kinc/threads/mutex.h>
#include <memory.h>
#include <stddef.h>
static kinc_mutex_t mutex;
static void (*a2_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata) = NULL;
static void *a2_userdata = NULL;
void kinc_a2_set_callback(void (*kinc_a2_audio_callback)(kinc_a2_buffer_t *buffer, uint32_t samples, void *userdata), void *userdata) {
kinc_mutex_lock(&mutex);
a2_callback = kinc_a2_audio_callback;
a2_userdata = userdata;
kinc_mutex_unlock(&mutex);
}
static void (*a2_sample_rate_callback)(void *userdata) = NULL;
static void *a2_sample_rate_userdata = NULL;
void kinc_a2_set_sample_rate_callback(void (*kinc_a2_sample_rate_callback)(void *userdata), void *userdata) {
kinc_mutex_lock(&mutex);
a2_sample_rate_callback = kinc_a2_sample_rate_callback;
a2_sample_rate_userdata = userdata;
kinc_mutex_unlock(&mutex);
}
void kinc_a2_internal_init(void) {
kinc_mutex_init(&mutex);
}
bool kinc_a2_internal_callback(kinc_a2_buffer_t *buffer, int samples) {
kinc_mutex_lock(&mutex);
bool has_callback = a2_callback != NULL;
if (has_callback) {
a2_callback(buffer, samples, a2_userdata);
}
kinc_mutex_unlock(&mutex);
return has_callback;
}
void kinc_a2_internal_sample_rate_callback(void) {
kinc_mutex_lock(&mutex);
if (a2_sample_rate_callback != NULL) {
a2_sample_rate_callback(a2_sample_rate_userdata);
}
kinc_mutex_unlock(&mutex);
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,46 @@
#pragma once
#include <kinc/global.h>
#include <stdint.h>
/*! \file color.h
\brief Provides some utility functionality for handling 32 bit ARGB color values.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Splits up an 32 bit ARGB color value into its components.
/// </summary>
KINC_FUNC void kinc_color_components(uint32_t color, float *red, float *green, float *blue, float *alpha);
#define KINC_COLOR_BLACK 0xff000000
#define KINC_COLOR_WHITE 0xffffffff
#define KINC_COLOR_RED 0xffff0000
#define KINC_COLOR_BLUE 0xff0000ff
#define KINC_COLOR_GREEN 0xff00ff00
#define KINC_COLOR_MAGENTA 0xffff00ff
#define KINC_COLOR_YELLOW 0xffffff00
#define KINC_COLOR_CYAN 0xff00ffff
#ifdef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
void kinc_color_components(uint32_t color, float *red, float *green, float *blue, float *alpha) {
*alpha = ((color & 0xff000000) >> 24) / 255.0f;
*red = ((color & 0x00ff0000) >> 16) / 255.0f;
*green = ((color & 0x0000ff00) >> 8) / 255.0f;
*blue = (color & 0x000000ff) / 255.0f;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,86 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
/*! \file display.h
\brief Provides information for the active displays.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_display_mode {
int x;
int y;
int width;
int height;
int pixels_per_inch;
int frequency;
int bits_per_pixel;
} kinc_display_mode_t;
/// <summary>
/// Allows retrieval of display values prior to the kinc_init call.
/// </summary>
KINC_FUNC void kinc_display_init(void);
/// <summary>
/// Retrieves the index of the primary display.
/// </summary>
/// <returns>The index of the primary display</returns>
KINC_FUNC int kinc_primary_display(void);
/// <summary>
/// Retrieves the number of displays connected to the system.
/// </summary>
/// <remarks>
/// All indices from 0 to kinc_count_displays() - 1 are legal display indices.
/// </remarks>
/// <returns>The number of displays connected to the system</returns>
KINC_FUNC int kinc_count_displays(void);
/// <summary>
/// Checks whether the display index points to an available display.
/// </summary>
/// <param name="display_index">Index of the display to check</param>
/// <returns>
/// Returns true if the index points to an available display,
/// false otherwise
/// </returns>
KINC_FUNC bool kinc_display_available(int display_index);
/// <summary>
/// Retrieves the system name of a display.
/// </summary>
/// <param name="display_index">Index of the display to retrieve the name from</param>
/// <returns>The system name of the display</returns>
KINC_FUNC const char *kinc_display_name(int display_index);
/// <summary>
/// Retrieves the current mode of a display.
/// </summary>
/// <param name="display_index">Index of the display to retrieve the mode from</param>
/// <returns>The current display mode</returns>
KINC_FUNC kinc_display_mode_t kinc_display_current_mode(int display_index);
/// <summary>
/// Retrieves the number of available modes of a display.
/// </summary>
/// <param name="display_index">Index of the display to retrieve the modes count from</param>
/// <returns>The number of available modes of the display</returns>
KINC_FUNC int kinc_display_count_available_modes(int display_index);
/// <summary>
/// Retrieves a specific mode of a display.
/// </summary>
/// <param name="display_index">Index of the display to retrieve the mode from</param>
/// <param name="mode_index">Index of the mode to retrieve</param>
/// <returns>The display mode</returns>
KINC_FUNC kinc_display_mode_t kinc_display_available_mode(int display_index, int mode_index);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,200 @@
#pragma once
#include <kinc/global.h>
#include <stdarg.h>
/*! \file error.h
\brief Contains functionality to stop the program in case of an error and create a user-visible error message.
The affirm and error functions print an error message and then exit the program. Error messages can be made
visible to the user (unless a console window is active this is only implemented for Windows).
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Exits the program when a condition is untrue and shows
/// a generic error message.
/// </summary>
/// <remarks>
/// This is an alternative to assert which also persists in release
/// builds. Use this instead of assert in situations where you want
/// your users to see what's going wrong.
/// This uses Kinc's log and error functionality to make errors
/// visible.
/// </remarks>
/// <param name="condition">
/// Exits the program if condition is false,
/// otherwise does nothing.
/// </param>
KINC_FUNC void kinc_affirm(bool condition);
/// <summary>
/// Exits the program when a condition is untrue and shows
/// a provided error message.
/// </summary>
/// <remarks>
/// This is equivalent to kinc_affirm() but uses the provided message
/// instead of a generic one.
/// </remarks>
/// <param name="condition">
/// Exits the program if condition is false,
/// otherwise does nothing.
/// </param>
/// <param name="format">
/// The parameter is equivalent to the first printf parameter.
/// </param>
/// <param name="...">
/// The parameter is equivalent to the second printf parameter.
/// </param>
KINC_FUNC void kinc_affirm_message(bool condition, const char *format, ...);
/// <summary>
/// Equivalent to kinc_affirm_message but uses a va_list parameter.
/// </summary>
/// <remarks>
/// You will need this if you want to provide the parameters using va_start/va_end.
/// </remarks>
/// <param name="condition">
/// Exits the program if condition is false,
/// otherwise does nothing.
/// </param>
/// <param name="format">
/// The parameter is equivalent to the first vprintf parameter.
/// </param>
/// <param name="...">
/// The parameter is equivalent to the second vprintf parameter.
/// </param>
KINC_FUNC void kinc_affirm_args(bool condition, const char *format, va_list args);
/// <summary>
/// Exits the program and shows a generic error message
/// </summary>
/// <remarks>
/// Mainly this just calls exit(EXIT_FAILURE) but will also use
/// Kore's log function and on Windows show an error message box.
/// </remarks>
KINC_FUNC void kinc_error(void);
/// <summary>
/// Exits the program and shows a provided error message.
/// </summary>
/// <remarks>
/// This is equivalent to kinc_error() but uses the provided message
/// instead of a generic one.
/// </remarks>
/// <param name="format">
/// The parameter is equivalent to the first printf parameter.
/// </param>
/// <param name="...">
/// The parameter is equivalent to the second printf parameter.
/// </param>
KINC_FUNC void kinc_error_message(const char *format, ...);
/// <summary>
/// Equivalent to kinc_error_message but uses a va_list parameter.
/// </summary>
/// <remarks>
/// You will need this if you want to provide the parameters using va_start/va_end.
/// </remarks>
/// <param name="format">
/// The parameter is equivalent to the first vprintf parameter.
/// </param>
/// <param name="...">
/// The parameter is equivalent to the second vprintf parameter.
/// </param>
KINC_FUNC void kinc_error_args(const char *format, va_list args);
#ifdef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#ifndef KINC_IMPLEMENTATION_ROOT
#undef KINC_IMPLEMENTATION
#endif
#include <kinc/log.h>
#ifndef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#include <stdlib.h>
#ifdef KINC_WINDOWS
#include <kinc/backend/MiniWindows.h>
#include <kinc/backend/SystemMicrosoft.h>
#endif
void kinc_affirm(bool condition) {
if (!condition) {
kinc_error();
}
}
void kinc_affirm_message(bool condition, const char *format, ...) {
if (!condition) {
va_list args;
va_start(args, format);
kinc_error_args(format, args);
va_end(args);
}
}
void kinc_affirm_args(bool condition, const char *format, va_list args) {
if (!condition) {
kinc_error_args(format, args);
}
}
void kinc_error(void) {
kinc_error_message("Unknown error");
}
void kinc_error_message(const char *format, ...) {
{
va_list args;
va_start(args, format);
kinc_log_args(KINC_LOG_LEVEL_ERROR, format, args);
va_end(args);
}
#ifdef KINC_WINDOWS
{
va_list args;
va_start(args, format);
wchar_t buffer[4096];
kinc_microsoft_format(format, args, buffer);
MessageBoxW(NULL, buffer, L"Error", 0);
va_end(args);
}
#endif
#ifndef KINC_NO_CLIB
exit(EXIT_FAILURE);
#endif
}
void kinc_error_args(const char *format, va_list args) {
kinc_log_args(KINC_LOG_LEVEL_ERROR, format, args);
#ifdef KINC_WINDOWS
wchar_t buffer[4096];
kinc_microsoft_format(format, args, buffer);
MessageBoxW(NULL, buffer, L"Error", 0);
#endif
#ifndef KINC_NO_CLIB
exit(EXIT_FAILURE);
#endif
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,146 @@
#pragma once
/*! \file global.h
\brief Provides basic functionality that's used all over the place. There's usually no need to manually include this.
*/
#include <stdbool.h>
#include <stdint.h>
#if defined(KINC_PPC)
#define KINC_BIG_ENDIAN
#else
#define KINC_LITTLE_ENDIAN
#endif
#if defined(KINC_PPC)
#define KINC_BIG_ENDIAN
#else
#define KINC_LITTLE_ENDIAN
#endif
#ifdef _MSC_VER
#define KINC_INLINE static __forceinline
#else
#define KINC_INLINE static __attribute__((always_inline)) inline
#endif
#ifdef _MSC_VER
#define KINC_MICROSOFT
#define KINC_MICROSOFT
#endif
#if defined(_WIN32)
#if defined(KINC_WINDOWSAPP)
#define KINC_WINDOWSAPP
#else
#ifndef KINC_CONSOLE
#define KINC_WINDOWS
#endif
#endif
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#if !defined(KINC_TVOS)
#define KINC_IOS
#endif
#define KINC_APPLE_SOC
#else
#define KINC_MACOS
#if defined(__arm64__)
#define KINC_APPLE_SOC
#endif
#endif
#define KINC_POSIX
#elif defined(__linux__)
#if !defined(KINC_ANDROID)
#define KINC_LINUX
#endif
#define KINC_POSIX
#endif
#ifdef KINC_WINDOWS
#if defined(KINC_DYNAMIC)
#define KINC_FUNC __declspec(dllimport)
#elif defined(KINC_DYNAMIC_COMPILE)
#define KINC_FUNC __declspec(dllexport)
#else
#define KINC_FUNC
#endif
#else
#define KINC_FUNC
#endif
#ifdef __cplusplus
namespace Kore {
typedef unsigned char u8; // 1 Byte
typedef unsigned short u16; // 2 Byte
typedef unsigned int u32; // 4 Byte
#if defined(__LP64__) || defined(_LP64) || defined(_WIN64)
#define KINC_64
#endif
#ifdef KINC_WINDOWS
typedef unsigned __int64 u64; // 8 Byte
#else
typedef unsigned long long u64;
#endif
typedef char s8; // 1 Byte
typedef short s16; // 2 Byte
typedef int s32; // 4 Byte
#ifdef KINC_WINDOWS
typedef __int64 s64; // 8 Byte
#else
typedef long long s64;
#endif
typedef u32 uint; // 4 Byte
typedef s32 sint; // 4 Byte
#ifdef KINC_64
typedef s64 spint;
typedef u64 upint;
#else
typedef s32 spint;
typedef u32 upint;
#endif
}
// pseudo C++11
#if !defined(_MSC_VER) && __cplusplus <= 199711L
#define nullptr 0
#define override
#endif
#define Noexcept throw()
#endif
#ifdef __cplusplus
extern "C" {
#endif
int kickstart(int argc, char **argv);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,175 @@
#include "graphics.h"
#include <kinc/graphics4/graphics.h>
#include <kinc/graphics4/indexbuffer.h>
#include <kinc/graphics4/pipeline.h>
#include <kinc/graphics4/shader.h>
#include <kinc/graphics4/texture.h>
#include <kinc/graphics4/vertexbuffer.h>
#include <kinc/io/filereader.h>
#ifdef KINC_KONG
#include <kong.h>
#endif
#ifndef KINC_KONG
static kinc_g4_shader_t vertexShader;
static kinc_g4_shader_t fragmentShader;
static kinc_g4_pipeline_t pipeline;
static kinc_g4_texture_unit_t tex;
#endif
static kinc_g4_vertex_buffer_t vb;
static kinc_g4_index_buffer_t ib;
static kinc_g4_texture_t texture;
uint32_t *kinc_internal_g1_image;
int kinc_internal_g1_w, kinc_internal_g1_h, kinc_internal_g1_tex_width;
void kinc_g1_begin(void) {
kinc_g4_begin(0);
kinc_internal_g1_image = (uint32_t *)kinc_g4_texture_lock(&texture);
}
void kinc_g1_end(void) {
kinc_internal_g1_image = NULL;
kinc_g4_texture_unlock(&texture);
kinc_g4_clear(KINC_G4_CLEAR_COLOR, 0xff000000, 0.0f, 0);
#ifdef KINC_KONG
kinc_g4_set_pipeline(&kinc_g1_pipeline);
#else
kinc_g4_set_pipeline(&pipeline);
#endif
#ifndef KINC_KONG
kinc_g4_set_texture(tex, &texture);
#endif
kinc_g4_set_vertex_buffer(&vb);
kinc_g4_set_index_buffer(&ib);
kinc_g4_draw_indexed_vertices();
kinc_g4_end(0);
kinc_g4_swap_buffers();
}
void kinc_g1_init(int width, int height) {
kinc_internal_g1_w = width;
kinc_internal_g1_h = height;
#ifndef KINC_KONG
{
kinc_file_reader_t file;
kinc_file_reader_open(&file, "g1.vert", KINC_FILE_TYPE_ASSET);
void *data = malloc(kinc_file_reader_size(&file));
kinc_file_reader_read(&file, data, kinc_file_reader_size(&file));
kinc_file_reader_close(&file);
kinc_g4_shader_init(&vertexShader, data, kinc_file_reader_size(&file), KINC_G4_SHADER_TYPE_VERTEX);
free(data);
}
{
kinc_file_reader_t file;
kinc_file_reader_open(&file, "g1.frag", KINC_FILE_TYPE_ASSET);
void *data = malloc(kinc_file_reader_size(&file));
kinc_file_reader_read(&file, data, kinc_file_reader_size(&file));
kinc_file_reader_close(&file);
kinc_g4_shader_init(&fragmentShader, data, kinc_file_reader_size(&file), KINC_G4_SHADER_TYPE_FRAGMENT);
free(data);
}
kinc_g4_vertex_structure_t structure;
kinc_g4_vertex_structure_init(&structure);
kinc_g4_vertex_structure_add(&structure, "pos", KINC_G4_VERTEX_DATA_F32_3X);
kinc_g4_vertex_structure_add(&structure, "tex", KINC_G4_VERTEX_DATA_F32_2X);
kinc_g4_pipeline_init(&pipeline);
pipeline.input_layout[0] = &structure;
pipeline.input_layout[1] = NULL;
pipeline.vertex_shader = &vertexShader;
pipeline.fragment_shader = &fragmentShader;
kinc_g4_pipeline_compile(&pipeline);
tex = kinc_g4_pipeline_get_texture_unit(&pipeline, "texy");
#endif
kinc_g4_texture_init(&texture, width, height, KINC_IMAGE_FORMAT_RGBA32);
kinc_internal_g1_tex_width = texture.tex_width;
kinc_internal_g1_image = (uint32_t *)kinc_g4_texture_lock(&texture);
int stride = kinc_g4_texture_stride(&texture) / 4;
for (int y = 0; y < texture.tex_height; ++y) {
for (int x = 0; x < texture.tex_width; ++x) {
kinc_internal_g1_image[y * stride + x] = 0;
}
}
kinc_g4_texture_unlock(&texture);
// Correct for the difference between the texture's desired size and the actual power of 2 size
float xAspect = (float)width / texture.tex_width;
float yAspect = (float)height / texture.tex_height;
#ifdef KINC_KONG
kinc_g4_vertex_buffer_init(&vb, 4, &kinc_g1_vertex_in_structure, KINC_G4_USAGE_STATIC, 0);
#else
kinc_g4_vertex_buffer_init(&vb, 4, &structure, KINC_G4_USAGE_STATIC, 0);
#endif
float *v = kinc_g4_vertex_buffer_lock_all(&vb);
{
int i = 0;
v[i++] = -1;
v[i++] = 1;
v[i++] = 0.5;
v[i++] = 0;
v[i++] = 0;
v[i++] = 1;
v[i++] = 1;
v[i++] = 0.5;
v[i++] = xAspect;
v[i++] = 0;
v[i++] = 1;
v[i++] = -1;
v[i++] = 0.5;
v[i++] = xAspect;
v[i++] = yAspect;
v[i++] = -1;
v[i++] = -1;
v[i++] = 0.5;
v[i++] = 0;
v[i++] = yAspect;
}
kinc_g4_vertex_buffer_unlock_all(&vb);
kinc_g4_index_buffer_init(&ib, 6, KINC_G4_INDEX_BUFFER_FORMAT_32BIT, KINC_G4_USAGE_STATIC);
uint32_t *ii = (uint32_t *)kinc_g4_index_buffer_lock_all(&ib);
{
int i = 0;
ii[i++] = 0;
ii[i++] = 1;
ii[i++] = 3;
ii[i++] = 1;
ii[i++] = 2;
ii[i++] = 3;
}
kinc_g4_index_buffer_unlock_all(&ib);
}
#if defined(KINC_DYNAMIC_COMPILE) || defined(KINC_DYNAMIC)
void kinc_g1_set_pixel(int x, int y, float red, float green, float blue) {
if (x < 0 || x >= kinc_internal_g1_w || y < 0 || y >= kinc_internal_g1_h)
return;
int r = (int)(red * 255);
int g = (int)(green * 255);
int b = (int)(blue * 255);
kinc_internal_g1_image[y * kinc_internal_g1_tex_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
}
int kinc_g1_width() {
return kinc_internal_g1_w;
}
int kinc_g1_height() {
return kinc_internal_g1_h;
}
#endif

View File

@ -0,0 +1,86 @@
#pragma once
#include <kinc/global.h>
#include <kinc/color.h>
#include <assert.h>
/*! \file graphics.h
\brief Supports a very basic pixel-setting API.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Initializes the G1-API.
/// </summary>
/// <param name="width">The width to be used by the G1-API - typically the window-width</param>
/// <param name="height">The height to be used by the G1-API - typically the window-height</param>
KINC_FUNC void kinc_g1_init(int width, int height);
/// <summary>
/// Typically called once per frame before other G1-functions are called.
/// </summary>
KINC_FUNC void kinc_g1_begin(void);
/// <summary>
/// Typically called once per frame after all G1-drawing is finished. This also swaps the framebuffers
/// so an equivalent call to kinc_g4_swap_buffers is not needed.
/// </summary>
KINC_FUNC void kinc_g1_end(void);
extern uint32_t *kinc_internal_g1_image;
extern int kinc_internal_g1_w, kinc_internal_g1_h, kinc_internal_g1_tex_width;
#if defined(KINC_DYNAMIC_COMPILE) || defined(KINC_DYNAMIC) || defined(KINC_DOCS)
/// <summary>
/// Sets a single pixel to a color.
/// </summary>
/// <param name="x">The x-component of the pixel-coordinate to set</param>
/// <param name="y">The y-component of the pixel-coordinate to set</param>
/// <param name="red">The red-component between 0 and 1</param>
/// <param name="green">The green-component between 0 and 1</param>
/// <param name="blue">The blue-component between 0 and 1</param>
KINC_FUNC void kinc_g1_set_pixel(int x, int y, float red, float green, float blue);
/// <summary>
/// Returns the width used by G1.
/// </summary>
/// <returns>The width</returns>
KINC_FUNC int kinc_g1_width(void);
/// <summary>
/// Returns the height used by G1.
/// </summary>
/// <returns>The height</returns>
KINC_FUNC int kinc_g1_height(void);
#else
// implementation moved to the header to allow easy inlining
static inline void kinc_g1_set_pixel(int x, int y, float red, float green, float blue) {
assert(x >= 0 && x < kinc_internal_g1_w && y >= 0 && y < kinc_internal_g1_h);
int r = (int)(red * 255);
int g = (int)(green * 255);
int b = (int)(blue * 255);
kinc_internal_g1_image[y * kinc_internal_g1_tex_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
}
static inline int kinc_g1_width(void) {
return kinc_internal_g1_w;
}
static inline int kinc_g1_height(void) {
return kinc_internal_g1_h;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,26 @@
#pragma once
#include <kinc/global.h>
#include <kinc/graphics4/texture.h>
#include <kinc/math/matrix.h>
/*! \file graphics.h
\brief This is still in progress, please don't use it.
*/
#ifdef __cplusplus
extern "C" {
#endif
void kinc_g2_init(int screen_width, int screen_height);
void kinc_g2_begin(void);
void kinc_g2_end(void);
void kinc_g2_clear(float r, float g, float b);
void kinc_g2_draw_image(kinc_image_t *img, float x, float y);
// void drawScaledSubImage(Graphics4::Texture *img, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh);
void kinc_g2_set_rotation(float angle, float centerx, float centery);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,44 @@
#include "graphics.h"
#include <kinc/graphics1/graphics.h>
#include <kinc/math/core.h>
#include <kinc/math/matrix.h>
#include <stdint.h>
#include <string.h>
#if 0
#include <Kore/Graphics2/Graphics.h>
static Kore::Graphics2::Graphics2 *kinc_kore_g2;
static kinc_matrix3x3_t transformation;
static Kore::Graphics4::Texture *tex;
void kinc_g2_init(int screen_width, int screen_height) {
tex = new Kore::Graphics4::Texture(32, 32, Kore::Graphics1::Image::RGBA32);
kinc_kore_g2 = new Kore::Graphics2::Graphics2(screen_width, screen_height);
}
void kinc_g2_begin(void) {
kinc_kore_g2->begin();
}
void kinc_g2_end(void) {
kinc_kore_g2->end();
}
void kinc_g2_draw_image(kinc_g4_texture_t *img, float x, float y) {
tex->kincTexture = *img;
tex->width = img->tex_width;
tex->height = img->tex_height;
tex->texWidth = img->tex_width;
tex->texHeight = img->tex_height;
kinc_kore_g2->drawImage(tex, x, y);
}
void kinc_g2_set_rotation(float angle, float centerx, float centery) {
kinc_kore_g2->transformation = (Kore::mat3::Translation(centerx, centery) * Kore::mat3::RotationZ(angle)) * Kore::mat3::Translation(-centerx, -centery);
}
#endif

View File

@ -0,0 +1,285 @@
#include "graphics.h"
#include <kinc/graphics1/graphics.h>
#include <kinc/math/core.h>
#include <kinc/math/matrix.h>
#include <stdint.h>
#include <string.h>
static kinc_matrix3x3_t transform;
void kinc_g2_init(int screen_width, int screen_height) {
kinc_g1_init(screen_width, screen_height);
transform = kinc_matrix3x3_identity();
}
void kinc_g2_begin(void) {
kinc_g1_begin();
}
void kinc_g2_end(void) {
kinc_g1_end();
}
void kinc_g2_clear(float r, float g, float b) {
memset(kinc_internal_g1_image, 0, kinc_internal_g1_tex_width * kinc_internal_g1_h * 4);
}
/*void kinc_g2_draw_image(kinc_image_t *img, float x, float y) {
int xi = (int)kinc_round(x);
int yi = (int)kinc_round(y);
uint32_t *data = (uint32_t *)img->data;
for (int yy = yi; yy < yi + img->height; ++yy) {
for (int xx = xi; xx < xi + img->width; ++xx) {
uint32_t pixel = data[(yy - yi) * img->width + (xx - xi)];
uint32_t alpha = pixel >> 24;
uint32_t blue = (pixel >> 16) & 0xff;
uint32_t green = (pixel >> 8) & 0xff;
uint32_t red = pixel & 0xff;
float rf = red / 255.0f;
float gf = green / 255.0f;
float bf = blue / 255.0f;
if (alpha == 0) {
// nothing
}
else if (alpha == 255) {
kinc_g1_set_pixel(xx, yy, rf, gf, bf);
}
else {
float a = alpha / 255.0f;
uint32_t old = kinc_internal_g1_image[(yy - yi) * kinc_internal_g1_tex_width + (xx - xi)];
float oldblue = ((old >> 16) & 0xff) / 255.0f;
float oldgreen = ((old >> 8) & 0xff) / 255.0f;
float oldred = (old & 0xff) / 255.0f;
kinc_g1_set_pixel(xx, yy, rf * a + oldred * (1.0f - a), gf * a + oldgreen * (1.0f - a), bf * a + oldblue * (1.0f - a));
}
}
}
}*/
static void draw_pixel_point(kinc_image_t *img, int frame_x, int frame_y, float u, float v) {
// int xi = (int)kinc_round(x);
// int yi = (int)kinc_round(y);
uint32_t *data = (uint32_t *)img->data;
int image_x = (int)kinc_round(u * (img->width - 1));
int image_y = (int)kinc_round(v * (img->height - 1));
uint32_t pixel = data[image_y * img->width + image_x];
uint32_t alpha = pixel >> 24;
uint32_t blue = (pixel >> 16) & 0xff;
uint32_t green = (pixel >> 8) & 0xff;
uint32_t red = pixel & 0xff;
float rf = red / 255.0f;
float gf = green / 255.0f;
float bf = blue / 255.0f;
if (alpha == 0) {
// nothing
}
else if (alpha == 255) {
kinc_g1_set_pixel(frame_x, frame_y, rf, gf, bf);
}
else {
float a = alpha / 255.0f;
uint32_t old = kinc_internal_g1_image[frame_y * kinc_internal_g1_tex_width + frame_x];
float oldblue = ((old >> 16) & 0xff) / 255.0f;
float oldgreen = ((old >> 8) & 0xff) / 255.0f;
float oldred = (old & 0xff) / 255.0f;
kinc_g1_set_pixel(frame_x, frame_y, rf * a + oldred * (1.0f - a), gf * a + oldgreen * (1.0f - a), bf * a + oldblue * (1.0f - a));
}
}
#if 0
static void draw_pixel_bilinear(kinc_image_t *img, int frame_x, int frame_y, float u, float v) {
// int xi = (int)kinc_round(x);
// int yi = (int)kinc_round(y);
uint32_t *data = (uint32_t *)img->data;
int image_x0 = (int)kinc_floor(u * (img->width - 1));
int image_y0 = (int)kinc_floor(v * (img->height - 1));
int image_x1 = kinc_mini(image_x0 + 1, img->width - 1);
int image_y1 = kinc_mini(image_y0 + 1, img->height - 1);
uint32_t pixel00 = data[image_y0 * img->width + image_x0];
uint32_t pixel01 = data[image_y1 * img->width + image_x0];
uint32_t pixel10 = data[image_y0 * img->width + image_x1];
uint32_t pixel11 = data[image_y1 * img->width + image_x1];
float alpha00 = (pixel00 >> 24) / 255.0f;
float blue00 = ((pixel00 >> 16) & 0xff) / 255.0f;
float green00 = ((pixel00 >> 8) & 0xff) / 255.0f;
float red00 = (pixel00 & 0xff) / 255.0f;
float alpha01 = (pixel01 >> 24) / 255.0f;
float blue01 = ((pixel01 >> 16) & 0xff) / 255.0f;
float green01 = ((pixel01 >> 8) & 0xff) / 255.0f;
float red01 = (pixel01 & 0xff) / 255.0f;
float alpha10 = (pixel10 >> 24) / 255.0f;
float blue10 = ((pixel10 >> 16) & 0xff) / 255.0f;
float green10 = ((pixel10 >> 8) & 0xff) / 255.0f;
float red10 = (pixel10 & 0xff) / 255.0f;
float alpha11 = (pixel11 >> 24) / 255.0f;
float blue11 = ((pixel11 >> 16) & 0xff) / 255.0f;
float green11 = ((pixel11 >> 8) & 0xff) / 255.0f;
float red11 = (pixel11 & 0xff) / 255.0f;
float xx = (u * (img->width - 1)) - image_x0;
float alpha0 = alpha00 * xx + alpha10 * (1.0f - xx);
float blue0 = blue00 * xx + blue10 * (1.0f - xx);
float green0 = green00 * xx + green10 * (1.0f - xx);
float red0 = red00 * xx + red10 * (1.0f - xx);
float alpha1 = alpha01 * xx + alpha11 * (1.0f - xx);
float blue1 = blue01 * xx + blue11 * (1.0f - xx);
float green1 = green01 * xx + green11 * (1.0f - xx);
float red1 = red01 * xx + red11 * (1.0f - xx);
float yy = (v * (img->height - 1)) - image_y0;
float a = alpha0 * yy + alpha1 * (1.0f - yy);
float rf = red0 * yy + red1 * (1.0f - yy);
float gf = green0 * yy + green1 * (1.0f - yy);
float bf = blue0 * yy + blue1 * (1.0f - yy);
// float rf = red / 255.0f;
// float gf = green / 255.0f;
// float bf = blue / 255.0f;
if (a == 0.0f) {
// nothing
}
else if (a == 1.0f) {
kinc_g1_set_pixel(frame_x, frame_y, rf, gf, bf);
}
else {
// float a = alpha / 255.0f;
uint32_t old = kinc_internal_g1_image[frame_y * kinc_internal_g1_tex_width + frame_x];
float oldblue = ((old >> 16) & 0xff) / 255.0f;
float oldgreen = ((old >> 8) & 0xff) / 255.0f;
float oldred = (old & 0xff) / 255.0f;
kinc_g1_set_pixel(frame_x, frame_y, rf * a + oldred * (1.0f - a), gf * a + oldgreen * (1.0f - a), bf * a + oldblue * (1.0f - a));
}
}
#endif
static void draw_pixel(kinc_image_t *img, int frame_x, int frame_y, float u, float v) {
draw_pixel_point(img, frame_x, frame_y, u, v);
}
typedef struct Point2D {
int x, y;
} Point2D_t;
static int orient2d(Point2D_t a, Point2D_t b, Point2D_t c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
}
static int min4(int a, int b, int c, int d) {
return kinc_mini(kinc_mini(a, b), kinc_mini(c, d));
}
static int max4(int a, int b, int c, int d) {
return kinc_maxi(kinc_maxi(a, b), kinc_maxi(c, d));
}
static void drawQuad(kinc_image_t *img, Point2D_t v0, Point2D_t v1, Point2D_t v2, Point2D_t v3) {
// Compute triangle bounding box
int minX = min4(v0.x, v1.x, v2.x, v3.x);
int minY = min4(v0.y, v1.y, v2.y, v3.y);
int maxX = max4(v0.x, v1.x, v2.x, v3.x);
int maxY = max4(v0.y, v1.y, v2.y, v3.y);
// Clip against screen bounds
minX = kinc_maxi(minX, 0);
minY = kinc_maxi(minY, 0);
maxX = kinc_mini(maxX, kinc_internal_g1_w - 1);
maxY = kinc_mini(maxY, kinc_internal_g1_h - 1);
// v1 - v0
int x1 = v1.x - v0.x;
int x2 = v1.y - v0.y;
// v2 - v1
int y1 = v2.x - v1.x;
int y2 = v2.y - v1.y;
int area = x1 * y2 - x2 * y1;
// Rasterize
Point2D_t p;
for (p.y = minY; p.y <= maxY; p.y++) {
for (p.x = minX; p.x <= maxX; p.x++) {
// Determine barycentric coordinates
int w0 = orient2d(v0, v1, p);
int w1 = orient2d(v1, v2, p);
// int w2 = orient2d(v2, v3, p);
// int w3 = orient2d(v3, v0, p);
float u = w0 / (float)area; //(w0 + w2);
float v = w1 / (float)area; //(w1 + w3);
// If p is on or inside all edges, render pixel.
// if (w0 >= 0 && w1 >= 0 && w2 >= 0 && w3 >= 0) {
if (u >= 0.0f && u <= 1.0f && v >= 0.0f && v <= 1.0f) {
// renderPixel(p, w0, w1, w2);
// kinc_g1_set_pixel(p.x, p.y, u, v, 0.0f);
draw_pixel(img, p.x, p.y, u, v);
}
}
}
}
void kinc_g2_draw_image(kinc_image_t *img, float x, float y) {
kinc_vector3_t _0;
_0.x = x;
_0.y = y;
_0.z = 1.0f;
kinc_vector3_t _1;
_1.x = x + img->width;
_1.y = y;
_1.z = 1.0f;
kinc_vector3_t _2;
_2.x = x + img->width;
_2.y = y + img->height;
_2.z = 1.0f;
kinc_vector3_t _3;
_3.x = x;
_3.y = y + img->height;
_3.z = 1.0f;
_0 = kinc_matrix3x3_multiply_vector(&transform, _0);
_1 = kinc_matrix3x3_multiply_vector(&transform, _1);
_2 = kinc_matrix3x3_multiply_vector(&transform, _2);
_3 = kinc_matrix3x3_multiply_vector(&transform, _3);
Point2D_t v0, v1, v2, v3;
v0.x = (int)kinc_round(_0.x);
v0.y = (int)kinc_round(_0.y);
v1.x = (int)kinc_round(_1.x);
v1.y = (int)kinc_round(_1.y);
v2.x = (int)kinc_round(_2.x);
v2.y = (int)kinc_round(_2.y);
v3.x = (int)kinc_round(_3.x);
v3.y = (int)kinc_round(_3.y);
drawQuad(img, v0, v1, v2, v3);
}
void kinc_g2_set_rotation(float angle, float centerx, float centery) {
kinc_matrix3x3_t translation1 = kinc_matrix3x3_translation(centerx, centery);
kinc_matrix3x3_t rotation = kinc_matrix3x3_rotation_z(angle);
kinc_matrix3x3_t translation2 = kinc_matrix3x3_translation(-centerx, -centery);
kinc_matrix3x3_t transformation1 = kinc_matrix3x3_multiply(&translation1, &rotation);
transform = kinc_matrix3x3_multiply(&transformation1, &translation2);
}

View File

@ -0,0 +1,74 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics4/compute.h>
#ifdef KINC_OPENGL
#include <kinc/backend/graphics4/ShaderStorageBufferImpl.h>
#include <kinc/graphics4/vertexbuffer.h>
#endif
#include <kinc/graphics4/graphics.h>
/*! \file compute.h
\brief Provides support for running compute-shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_g4_texture;
struct kinc_g4_render_target;
typedef struct kinc_g4_compute_shader {
kinc_g4_compute_shader_impl impl;
} kinc_g4_compute_shader;
/// <summary>
/// Initialize a compute-shader from system-specific shader-data.
/// </summary>
/// <param name="shader">The shader-object to initialize</param>
/// <param name="source">A pointer to system-specific shader-data</param>
/// <param name="length">Length of the shader-data in bytes</param>
KINC_FUNC void kinc_g4_compute_shader_init(kinc_g4_compute_shader *shader, void *source, int length);
/// <summary>
/// Destroy a shader-object
/// </summary>
/// <param name="shader">The shader-object to destroy</param>
KINC_FUNC void kinc_g4_compute_shader_destroy(kinc_g4_compute_shader *shader);
#ifndef KINC_KONG
/// <summary>
/// Finds the location of a constant/uniform inside of a shader.
/// </summary>
/// <param name="shader">The shader to look into</param>
/// <param name="name">The constant/uniform-name to look for</param>
/// <returns>The found constant-location</returns>
KINC_FUNC kinc_g4_constant_location_t kinc_g4_compute_shader_get_constant_location(kinc_g4_compute_shader *shader, const char *name);
/// <summary>
/// Finds a texture-unit inside of a shader.
/// </summary>
/// <param name="shader">The shader to look into</param>
/// <param name="name">The texture-name to look for</param>
/// <returns>The found texture-unit</returns>
KINC_FUNC kinc_g4_texture_unit_t kinc_g4_compute_shader_get_texture_unit(kinc_g4_compute_shader *shader, const char *name);
#endif
#ifdef KINC_OPENGL
typedef struct kinc_shader_storage_buffer {
kinc_compute_shader_storage_buffer_impl_t impl;
} kinc_shader_storage_buffer_t;
KINC_FUNC void kinc_shader_storage_buffer_init(kinc_shader_storage_buffer_t *buffer, int count, kinc_g4_vertex_data_t type);
KINC_FUNC void kinc_shader_storage_buffer_destroy(kinc_shader_storage_buffer_t *buffer);
KINC_FUNC int *kinc_shader_storage_buffer_lock(kinc_shader_storage_buffer_t *buffer);
KINC_FUNC void kinc_shader_storage_buffer_unlock(kinc_shader_storage_buffer_t *buffer);
KINC_FUNC int kinc_shader_storage_buffer_count(kinc_shader_storage_buffer_t *buffer);
KINC_FUNC void kinc_shader_storage_buffer_internal_set(kinc_shader_storage_buffer_t *buffer);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,77 @@
#pragma once
#ifdef KINC_KONG
#include <kinc/global.h>
#include <kinc/backend/graphics4/constantbuffer.h>
#include <kinc/math/matrix.h>
#include <kinc/math/vector.h>
/*! \file constantbuffer.h
\brief Provides support for managing buffers of constant-data for shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g4_constant_buffer {
kinc_g4_constant_buffer_impl impl;
} kinc_g4_constant_buffer;
/// <summary>
/// Initializes a constant-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="size">The size of the constant-data in the buffer in bytes</param>
KINC_FUNC void kinc_g4_constant_buffer_init(kinc_g4_constant_buffer *buffer, size_t size);
/// <summary>
/// Destroys a buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g4_constant_buffer_destroy(kinc_g4_constant_buffer *buffer);
/// <summary>
/// Locks all of a constant-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the buffer</returns>
KINC_FUNC uint8_t *kinc_g4_constant_buffer_lock_all(kinc_g4_constant_buffer *buffer);
/// <summary>
/// Locks part of a constant-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The offset of where to start the lock in bytes</param>
/// <param name="count">The number of bytes to lock</param>
/// <returns>The contents of the buffer, starting at start</returns>
KINC_FUNC uint8_t *kinc_g4_constant_buffer_lock(kinc_g4_constant_buffer *buffer, size_t start, size_t count);
/// <summary>
/// Unlocks a constant-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g4_constant_buffer_unlock_all(kinc_g4_constant_buffer *buffer);
/// <summary>
/// Unlocks parts of a constant-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
/// /// <param name="count">The number of bytes to unlock, starting from the start-index from the previous lock-call</param>
KINC_FUNC void kinc_g4_constant_buffer_unlock(kinc_g4_constant_buffer *buffer, size_t count);
/// <summary>
/// Figures out the size of the constant-data in the buffer.
/// </summary>
/// <param name="buffer">The buffer to figure out the size for</param>
/// <returns>Returns the size of the constant-data in the buffer in bytes</returns>
KINC_FUNC size_t kinc_g4_constant_buffer_size(kinc_g4_constant_buffer *buffer);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,22 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics4/pipeline.h>
#include <kinc/backend/graphics4/shader.h>
/*! \file constantlocation.h
\brief Provides the constant_location-struct which is used for setting constants/uniforms in a shader.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g4_constant_location {
kinc_g4_constant_location_impl_t impl;
} kinc_g4_constant_location_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
#include "graphics.c.h"
#include "pipeline.c.h"
#include "rendertarget.c.h"
#include "vertexbuffer.c.h"

View File

@ -0,0 +1,11 @@
#include "graphics.h"
static int antialiasing_samples;
int kinc_g4_antialiasing_samples(void) {
return antialiasing_samples;
}
void kinc_g4_set_antialiasing_samples(int samples) {
antialiasing_samples = samples;
}

View File

@ -0,0 +1,457 @@
#pragma once
#include <kinc/global.h>
#include <kinc/math/matrix.h>
#include "constantlocation.h"
#include "pipeline.h"
#include "textureunit.h"
/*! \file graphics.h
\brief Contains the base G4-functionality.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_g4_compute_shader;
struct kinc_g4_pipeline;
struct kinc_g4_render_target;
struct kinc_g4_texture;
struct kinc_g4_texture_array;
#ifdef KINC_OPENGL
struct kinc_shader_storage_buffer;
#endif
#ifdef KINC_KONG
struct kinc_g4_constant_buffer;
#endif
typedef enum {
KINC_G4_TEXTURE_ADDRESSING_REPEAT,
KINC_G4_TEXTURE_ADDRESSING_MIRROR,
KINC_G4_TEXTURE_ADDRESSING_CLAMP,
KINC_G4_TEXTURE_ADDRESSING_BORDER
} kinc_g4_texture_addressing_t;
typedef enum { KINC_G4_TEXTURE_DIRECTION_U, KINC_G4_TEXTURE_DIRECTION_V, KINC_G4_TEXTURE_DIRECTION_W } kinc_g4_texture_direction_t;
typedef enum { KINC_G4_TEXTURE_FILTER_POINT, KINC_G4_TEXTURE_FILTER_LINEAR, KINC_G4_TEXTURE_FILTER_ANISOTROPIC } kinc_g4_texture_filter_t;
typedef enum {
KINC_G4_MIPMAP_FILTER_NONE,
KINC_G4_MIPMAP_FILTER_POINT,
KINC_G4_MIPMAP_FILTER_LINEAR // linear texture filter + linear mip filter -> trilinear filter
} kinc_g4_mipmap_filter_t;
/// <summary>
/// Returns whether instanced rendering (kinc_g4_draw_indexed_vertices_instanced and pals) is supported.
/// </summary>
/// <returns>Whether instanced rendering is supported</returns>
KINC_FUNC bool kinc_g4_supports_instanced_rendering(void);
/// <summary>
/// Returns whether GPU-compute (the functions in kinc/compute/compute.h) is supported.
/// </summary>
/// <returns>Whether GPU-compute is supported</returns>
KINC_FUNC bool kinc_g4_supports_compute_shaders(void);
/// <summary>
/// Returns whether blend-constants (see kinc_g4_set_blend_constant and the blending-properties for pipelines) are supported.
/// </summary>
/// <returns>Whether blend-constants are supported</returns>
KINC_FUNC bool kinc_g4_supports_blend_constants(void);
/// <summary>
/// Returns whether textures are supported which have widths/heights which are not powers of two.
/// </summary>
/// <returns>Whether non power of two texture-sizes are supported</returns>
KINC_FUNC bool kinc_g4_supports_non_pow2_textures(void);
/// <summary>
/// Returns whether render-targets are upside down. This happens in OpenGL and there is currently no automatic mitigation.
/// </summary>
/// <returns>Whether render-targets are upside down</returns>
KINC_FUNC bool kinc_g4_render_targets_inverted_y(void);
/// <summary>
/// Returns how many textures can be used at the same time in a fragment-shader.
/// </summary>
/// <returns>The number of textures</returns>
KINC_FUNC int kinc_g4_max_bound_textures(void);
/// <summary>
/// Kicks off lingering work - may or may not actually do anything depending on the underlying graphics-API.
/// </summary>
KINC_FUNC void kinc_g4_flush(void);
/// <summary>
/// Needs to be called before rendering to a window. Typically called at the start of each frame.
/// </summary>
/// <param name="window">The window to render to</param>
KINC_FUNC void kinc_g4_begin(int window);
/// <summary>
/// Needs to be called after rendering to a window. Typically called at the end of each frame.
/// </summary>
/// <param name="window">The window to render to</param>
/// <returns></returns>
KINC_FUNC void kinc_g4_end(int window);
/// <summary>
/// Needs to be called to make the rendered frame visible. Typically called at the very end of each frame.
/// </summary>
KINC_FUNC bool kinc_g4_swap_buffers(void);
#define KINC_G4_CLEAR_COLOR 1
#define KINC_G4_CLEAR_DEPTH 2
#define KINC_G4_CLEAR_STENCIL 4
/// <summary>
/// Clears the color, depth and/or stencil-components of the current framebuffer or render-target.
/// </summary>
/// <param name="flags">Defines what components to clear</param>
/// <param name="color">The color-value to clear to in 0xAARRGGBB</param>
/// <param name="depth">The depth-value to clear to</param>
/// <param name="stencil">The stencil-value to clear to</param>
KINC_FUNC void kinc_g4_clear(unsigned flags, unsigned color, float depth, int stencil);
/// <summary>
/// Sets the viewport which defines the portion of the framebuffer or render-target things are rendered into. By default the viewport is equivalent to the full
/// size of the current render-target or framebuffer.
/// </summary>
/// <param name="x">The x-offset of the viewport from the left of the screen in pixels</param>
/// <param name="y">The y-offset of the viewport from the top of the screen in pixels</param>
/// <param name="width">The width of the viewport in pixels</param>
/// <param name="height">The height of the viewport in pixels</param>
KINC_FUNC void kinc_g4_viewport(int x, int y, int width, int height);
/// <summary>
/// Enables and defines the scissor-rect. When the scissor-rect is enabled, anything that's rendered outside of the scissor-rect will be ignored.
/// </summary>
/// <param name="x">The x-offset of the scissor-rect from the left of the screen in pixels</param>
/// <param name="y">The y-offset of the scissor-rect from the top of the screen in pixels</param>
/// <param name="width">The width of the scissor-rect in pixels</param>
/// <param name="height">The height of the scissor-rect in pixels</param>
KINC_FUNC void kinc_g4_scissor(int x, int y, int width, int height);
/// <summary>
/// Disables the scissor-rect.
/// </summary>
KINC_FUNC void kinc_g4_disable_scissor(void);
/// <summary>
/// Draws the entire content of the currently set index-buffer and vertex-buffer. G4 can only draw triangle-lists using vertex-indices as this is what GPUs tend
/// to be optimized for.
/// </summary>
KINC_FUNC void kinc_g4_draw_indexed_vertices(void);
/// <summary>
/// Draws a part of the content of the currently set index-buffer and vertex-buffer. G4 can only draw triangle-lists using vertex-indices as this is what GPUs
/// tend to be optimized for.
/// </summary>
/// <param name="start">The offset into the index-buffer</param>
/// <param name="count">The number of indices to use</param>
KINC_FUNC void kinc_g4_draw_indexed_vertices_from_to(int start, int count);
/// <summary>
/// Draws a part of the content of the currently set index-buffer and vertex-buffer and additionally applies a general offset into the vertex-buffer. G4 can
/// only draw triangle-lists using vertex-indices as this is what GPUs tend to be optimized for.
/// </summary>
/// <param name="start">The offset into the index-buffer</param>
/// <param name="count">The number of indices to use</param>
/// <param name="vertex_offset">The offset into the vertex-buffer which is added to each index read from the index-buffer</param>
KINC_FUNC void kinc_g4_draw_indexed_vertices_from_to_from(int start, int count, int vertex_offset);
KINC_FUNC void kinc_g4_draw_indexed_vertices_instanced(int instanceCount);
KINC_FUNC void kinc_g4_draw_indexed_vertices_instanced_from_to(int instanceCount, int start, int count);
KINC_FUNC void kinc_g4_set_texture_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing);
KINC_FUNC void kinc_g4_set_texture3d_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing);
/// <summary>
/// Sets the pipeline for the next draw-call. The pipeline defines most rendering-state including the shaders to be used.
/// </summary>
/// <param name="pipeline">The pipeline to set</param>
KINC_FUNC void kinc_g4_set_pipeline(struct kinc_g4_pipeline *pipeline);
KINC_FUNC void kinc_g4_set_stencil_reference_value(int value);
/// <summary>
/// Sets the blend constant used for `KINC_G4_BLEND_CONSTANT` or `KINC_G4_INV_BLEND_CONSTANT`
/// </summary>
KINC_FUNC void kinc_g4_set_blend_constant(float r, float g, float b, float a);
#ifdef KINC_KONG
KINC_FUNC void kinc_g4_set_constant_buffer(uint32_t id, struct kinc_g4_constant_buffer *buffer);
#endif
/// <summary>
/// Assigns an integer to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the value to</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_int(kinc_g4_constant_location_t location, int value);
/// <summary>
/// Assigns two integers to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first component of the constant/uniform</param>
/// <param name="value2">The value to assign to the second component of the constant/uniform</param>
KINC_FUNC void kinc_g4_set_int2(kinc_g4_constant_location_t location, int value1, int value2);
/// <summary>
/// Assigns three integers to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first component of the constant/uniform</param>
/// <param name="value2">The value to assign to the second component of the constant/uniform</param>
/// <param name="value3">The value to assign to the third component of the constant/uniform</param>
KINC_FUNC void kinc_g4_set_int3(kinc_g4_constant_location_t location, int value1, int value2, int value3);
/// <summary>
/// Assigns four integers to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first component of the constant/uniform</param>
/// <param name="value2">The value to assign to the second component of the constant/uniform</param>
/// <param name="value3">The value to assign to the third component of the constant/uniform</param>
/// <param name="value4">The value to assign to the fourth component of the constant/uniform</param>
KINC_FUNC void kinc_g4_set_int4(kinc_g4_constant_location_t location, int value1, int value2, int value3, int value4);
/// <summary>
/// Assigns a bunch of integers to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value">The values to assign to the constant/uniform</param>
/// <param name="value">The number of values to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_ints(kinc_g4_constant_location_t location, int *values, int count);
/// <summary>
/// Assigns a float to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the value to</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_float(kinc_g4_constant_location_t location, float value);
/// <summary>
/// Assigns two floats to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first constant/uniform</param>
/// <param name="value2">The value to assign to the second constant/uniform</param>
KINC_FUNC void kinc_g4_set_float2(kinc_g4_constant_location_t location, float value1, float value2);
/// <summary>
/// Assigns three floats to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first constant/uniform</param>
/// <param name="value2">The value to assign to the second constant/uniform</param>
/// <param name="value3">The value to assign to the third constant/uniform</param>
KINC_FUNC void kinc_g4_set_float3(kinc_g4_constant_location_t location, float value1, float value2, float value3);
/// <summary>
/// Assigns four floats to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value1">The value to assign to the first constant/uniform</param>
/// <param name="value2">The value to assign to the second constant/uniform</param>
/// <param name="value3">The value to assign to the third constant/uniform</param>
/// <param name="value4">The value to assign to the fourth constant/uniform</param>
KINC_FUNC void kinc_g4_set_float4(kinc_g4_constant_location_t location, float value1, float value2, float value3, float value4);
/// <summary>
/// Assigns a bunch of floats to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value">The values to assign to the constant/uniform</param>
/// <param name="value">The number of values to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_floats(kinc_g4_constant_location_t location, float *values, int count);
/// <summary>
/// Assigns a bool to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the value to</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_bool(kinc_g4_constant_location_t location, bool value);
/// <summary>
/// Assigns a 3x3-matrix to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the value to</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_matrix3(kinc_g4_constant_location_t location, kinc_matrix3x3_t *value);
/// <summary>
/// Assigns a 4x4-matrix to a constant/uniform in the currently set pipeline.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the value to</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g4_set_matrix4(kinc_g4_constant_location_t location, kinc_matrix4x4_t *value);
/// <summary>
/// Set the texture-sampling-mode for upscaled textures.
/// </summary>
/// <param name="unit">The texture-unit to set the texture-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture_magnification_filter(kinc_g4_texture_unit_t unit, kinc_g4_texture_filter_t filter);
/// <summary>
/// Set the texture-sampling-mode for upscaled 3D-textures.
/// </summary>
/// <param name="unit">The texture-unit to set the texture-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture3d_magnification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter);
/// <summary>
/// Set the texture-sampling-mode for downscaled textures.
/// </summary>
/// <param name="unit">The texture-unit to set the texture-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture_minification_filter(kinc_g4_texture_unit_t unit, kinc_g4_texture_filter_t filter);
/// <summary>
/// Set the texture-sampling-mode for downscaled 3D-textures.
/// </summary>
/// <param name="unit">The texture-unit to set the texture-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture3d_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter);
/// <summary>
/// Sets the mipmap-sampling-mode which defines whether mipmaps are used at all and if so whether the two neighbouring mipmaps are linearly interpolated.
/// </summary>
/// <param name="unit">The texture-unit to set the mipmap-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture_mipmap_filter(kinc_g4_texture_unit_t unit, kinc_g4_mipmap_filter_t filter);
/// <summary>
/// Sets the mipmap-sampling-mode for a 3D-texture which defines whether mipmaps are used at all and if so whether the two neighbouring mipmaps are linearly
/// interpolated.
/// </summary>
/// <param name="unit">The texture-unit to set the mipmap-sampling-mode for</param>
/// <param name="filter">The mode to set</param>
KINC_FUNC void kinc_g4_set_texture3d_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter);
KINC_FUNC void kinc_g4_set_texture_compare_mode(kinc_g4_texture_unit_t unit, bool enabled);
KINC_FUNC void kinc_g4_set_texture_compare_func(kinc_g4_texture_unit_t unit, kinc_g4_compare_mode_t mode);
KINC_FUNC void kinc_g4_set_cubemap_compare_mode(kinc_g4_texture_unit_t unit, bool enabled);
KINC_FUNC void kinc_g4_set_cubemap_compare_func(kinc_g4_texture_unit_t unit, kinc_g4_compare_mode_t mode);
KINC_FUNC void kinc_g4_set_texture_max_anisotropy(kinc_g4_texture_unit_t unit, uint16_t max_anisotropy);
KINC_FUNC void kinc_g4_set_cubemap_max_anisotropy(kinc_g4_texture_unit_t unit, uint16_t max_anisotropy);
KINC_FUNC void kinc_g4_set_texture_lod(kinc_g4_texture_unit_t unit, float lod_min_clamp, float lod_max_clamp);
KINC_FUNC void kinc_g4_set_cubemap_lod(kinc_g4_texture_unit_t unit, float lod_min_clamp, float lod_max_clamp);
/// <summary>
/// Sets the framebuffer (aka the actual contents of the current window) to be the target of any future draw-calls.
/// </summary>
KINC_FUNC void kinc_g4_restore_render_target(void);
/// <summary>
/// Sets the passed render-targets to be the target of any future draw-calls.
/// </summary>
/// <param name="targets">An array of render-targets</param>
/// <param name="count">The number of render-targets in the render-target-array</param>
KINC_FUNC void kinc_g4_set_render_targets(struct kinc_g4_render_target **targets, int count);
KINC_FUNC void kinc_g4_set_render_target_face(struct kinc_g4_render_target *texture, int face);
#ifdef KINC_KONG
/// <summary>
/// Assigns a texture to a texture-unit for sampled access via GLSL's texture.
/// </summary>
/// <param name="unit">The unit to assign this texture to</param>
/// <param name="texture">The texture to assign to the unit</param>
KINC_FUNC void kinc_g4_set_texture(uint32_t unit, struct kinc_g4_texture *texture);
#else
/// <summary>
/// Assigns a texture to a texture-unit for sampled access via GLSL's texture.
/// </summary>
/// <param name="unit">The unit to assign this texture to</param>
/// <param name="texture">The texture to assign to the unit</param>
KINC_FUNC void kinc_g4_set_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture);
#endif
/// <summary>
/// Assigns a texture to a texture-unit for direct access via GLSL's texelFetch (as
/// opposed to GLSL's texture). The name of this functions is unfortunately based
/// on OpenGL's confusing terminology.
/// </summary>
/// <param name="unit">The unit to assign this texture to</param>
/// <param name="texture">The texture to assign to the unit</param>
KINC_FUNC void kinc_g4_set_image_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture);
KINC_FUNC bool kinc_g4_init_occlusion_query(unsigned *occlusionQuery);
KINC_FUNC void kinc_g4_delete_occlusion_query(unsigned occlusionQuery);
KINC_FUNC void kinc_g4_start_occlusion_query(unsigned occlusionQuery);
KINC_FUNC void kinc_g4_end_occlusion_query(unsigned occlusionQuery);
KINC_FUNC bool kinc_g4_are_query_results_available(unsigned occlusionQuery);
KINC_FUNC void kinc_g4_get_query_results(unsigned occlusionQuery, unsigned *pixelCount);
/// <summary>
/// Assigns a texture-array to a texture-unit.
/// </summary>
/// <param name="unit">The unit to assign the texture-array to</param>
/// <param name="array">The texture-array to assign to the texture-unit</param>
KINC_FUNC void kinc_g4_set_texture_array(kinc_g4_texture_unit_t unit, struct kinc_g4_texture_array *array);
/// <summary>
/// Returns the currently used number of samples for hardware-antialiasing.
/// </summary>
/// <returns>The number of samples</returns>
KINC_FUNC int kinc_g4_antialiasing_samples(void);
/// <summary>
/// Sets the number of samples used for hardware-antialiasing. This typically uses multisampling and typically only works with a few specific numbers of
/// sample-counts - 2 and 4 are pretty safe bets. It also might do nothing at all.
/// </summary>
/// <param name="samples">The number of samples</param>
KINC_FUNC void kinc_g4_set_antialiasing_samples(int samples);
#ifdef KINC_OPENGL
/// <summary>
/// Old, hack thing, do not use.
/// </summary>
KINC_FUNC void kinc_g4_set_shader_storage_buffer(struct kinc_shader_storage_buffer *buffer, int index);
#endif
/// <summary>
/// Sets a shader for the next compute-run.
/// </summary>
/// <param name="shader">The shader to use</param>
KINC_FUNC void kinc_g4_set_compute_shader(struct kinc_g4_compute_shader *shader);
/// <summary>
/// Fire off a compute-run on x * y * z elements.
/// </summary>
/// <param name="x">The x-size for the compute-run</param>
/// <param name="y">The y-size for the compute-run</param>
/// <param name="z">The z-size for the compute-run</param>
KINC_FUNC void kinc_g4_compute(int x, int y, int z);
#ifndef KINC_DOCS
void kinc_g4_internal_init(void);
void kinc_g4_internal_init_window(int window, int depth_buffer_bits, int stencil_buffer_bits, bool vsync);
void kinc_g4_internal_destroy_window(int window);
void kinc_g4_internal_destroy(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,84 @@
#pragma once
#include <kinc/global.h>
#include "usage.h"
#include <kinc/backend/graphics4/indexbuffer.h>
/*! \file indexbuffer.h
\brief Provides functions for setting up and using index-buffers.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g4_index_buffer_format { KINC_G4_INDEX_BUFFER_FORMAT_32BIT, KINC_G4_INDEX_BUFFER_FORMAT_16BIT } kinc_g4_index_buffer_format_t;
typedef struct kinc_g4_index_buffer {
kinc_g4_index_buffer_impl_t impl;
} kinc_g4_index_buffer_t;
/// <summary>
/// Initializes an index-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="count">The number of indices to allocate for the buffer</param>
/// <param name="format">The integer-format of the buffer</param>
/// <param name="usage">A hint for how the buffer will be used</param>
KINC_FUNC void kinc_g4_index_buffer_init(kinc_g4_index_buffer_t *buffer, int count, kinc_g4_index_buffer_format_t format, kinc_g4_usage_t usage);
/// <summary>
/// Destroys an index-buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g4_index_buffer_destroy(kinc_g4_index_buffer_t *buffer);
/// <summary>
/// Locks an index-buffer so its contents can be modified.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the index-buffer in uint32s or uint16s depending on the format provided when initializing</returns>
KINC_FUNC void *kinc_g4_index_buffer_lock_all(kinc_g4_index_buffer_t *buffer);
/// <summary>
/// Locks part of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The index of the first index to lock</param>
/// <param name="count">The number of indices to lock</param>
/// <returns>The contents of the index-buffer, starting at start, in uint32s or uint16s depending on the format provided when initializing</returns>
KINC_FUNC void *kinc_g4_index_buffer_lock(kinc_g4_index_buffer_t *buffer, int start, int count);
/// <summary>
/// Unlocks an index-buffer after locking it so the changed buffer-contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g4_index_buffer_unlock_all(kinc_g4_index_buffer_t *buffer);
/// <summary>
/// Unlocks part of an index-buffer after locking so the changed buffer-contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
/// <param name="count">The number of indices to unlock, starting from the start-index from the previous lock-call</param>
KINC_FUNC void kinc_g4_index_buffer_unlock(kinc_g4_index_buffer_t *buffer, int count);
/// <summary>
/// Returns the number of indices in the buffer.
/// </summary>
/// <param name="buffer">The buffer to query for its number of indices</param>
/// <returns>The number of indices</returns>
KINC_FUNC int kinc_g4_index_buffer_count(kinc_g4_index_buffer_t *buffer);
void kinc_internal_g4_index_buffer_set(kinc_g4_index_buffer_t *buffer);
/// <summary>
/// Sets an index-buffer to be used for the next draw-command.
/// </summary>
/// <param name="buffer">The buffer to use</param>
KINC_FUNC void kinc_g4_set_index_buffer(kinc_g4_index_buffer_t *buffer);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,55 @@
#include "pipeline.h"
#include <stddef.h>
void kinc_g4_internal_pipeline_set_defaults(kinc_g4_pipeline_t *state) {
for (int i = 0; i < 16; ++i)
state->input_layout[i] = NULL;
state->vertex_shader = NULL;
state->fragment_shader = NULL;
state->geometry_shader = NULL;
state->tessellation_control_shader = NULL;
state->tessellation_evaluation_shader = NULL;
state->cull_mode = KINC_G4_CULL_NOTHING;
state->depth_write = false;
state->depth_mode = KINC_G4_COMPARE_ALWAYS;
state->stencil_front_mode = KINC_G4_COMPARE_ALWAYS;
state->stencil_front_both_pass = KINC_G4_STENCIL_KEEP;
state->stencil_front_depth_fail = KINC_G4_STENCIL_KEEP;
state->stencil_front_fail = KINC_G4_STENCIL_KEEP;
state->stencil_back_mode = KINC_G4_COMPARE_ALWAYS;
state->stencil_back_both_pass = KINC_G4_STENCIL_KEEP;
state->stencil_back_depth_fail = KINC_G4_STENCIL_KEEP;
state->stencil_back_fail = KINC_G4_STENCIL_KEEP;
state->stencil_reference_value = 0;
state->stencil_read_mask = 0xff;
state->stencil_write_mask = 0xff;
state->blend_source = KINC_G4_BLEND_ONE;
state->blend_destination = KINC_G4_BLEND_ZERO;
state->blend_operation = KINC_G4_BLENDOP_ADD;
state->alpha_blend_source = KINC_G4_BLEND_ONE;
state->alpha_blend_destination = KINC_G4_BLEND_ZERO;
state->alpha_blend_operation = KINC_G4_BLENDOP_ADD;
for (int i = 0; i < 8; ++i)
state->color_write_mask_red[i] = true;
for (int i = 0; i < 8; ++i)
state->color_write_mask_green[i] = true;
for (int i = 0; i < 8; ++i)
state->color_write_mask_blue[i] = true;
for (int i = 0; i < 8; ++i)
state->color_write_mask_alpha[i] = true;
state->color_attachment_count = 1;
for (int i = 0; i < 8; ++i)
state->color_attachment[i] = KINC_G4_RENDER_TARGET_FORMAT_32BIT;
state->depth_attachment_bits = 0;
state->stencil_attachment_bits = 0;
state->conservative_rasterization = false;
}

View File

@ -0,0 +1,161 @@
#pragma once
#include <kinc/global.h>
#include <kinc/graphics4/constantlocation.h>
#include <kinc/graphics4/rendertarget.h>
#include <kinc/graphics4/textureunit.h>
#include <kinc/backend/graphics4/pipeline.h>
/*! \file pipeline.h
\brief Provides functions for creating and using pipelines which configure the GPU for rendering.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_g4_vertex_structure;
struct kinc_g4_shader;
typedef enum {
KINC_G4_BLEND_ONE,
KINC_G4_BLEND_ZERO,
KINC_G4_BLEND_SOURCE_ALPHA,
KINC_G4_BLEND_DEST_ALPHA,
KINC_G4_BLEND_INV_SOURCE_ALPHA,
KINC_G4_BLEND_INV_DEST_ALPHA,
KINC_G4_BLEND_SOURCE_COLOR,
KINC_G4_BLEND_DEST_COLOR,
KINC_G4_BLEND_INV_SOURCE_COLOR,
KINC_G4_BLEND_INV_DEST_COLOR,
KINC_G4_BLEND_CONSTANT,
KINC_G4_BLEND_INV_CONSTANT
} kinc_g4_blending_factor_t;
typedef enum {
KINC_G4_BLENDOP_ADD,
KINC_G4_BLENDOP_SUBTRACT,
KINC_G4_BLENDOP_REVERSE_SUBTRACT,
KINC_G4_BLENDOP_MIN,
KINC_G4_BLENDOP_MAX
} kinc_g4_blending_operation_t;
typedef enum {
KINC_G4_COMPARE_ALWAYS,
KINC_G4_COMPARE_NEVER,
KINC_G4_COMPARE_EQUAL,
KINC_G4_COMPARE_NOT_EQUAL,
KINC_G4_COMPARE_LESS,
KINC_G4_COMPARE_LESS_EQUAL,
KINC_G4_COMPARE_GREATER,
KINC_G4_COMPARE_GREATER_EQUAL
} kinc_g4_compare_mode_t;
typedef enum { KINC_G4_CULL_CLOCKWISE, KINC_G4_CULL_COUNTER_CLOCKWISE, KINC_G4_CULL_NOTHING } kinc_g4_cull_mode_t;
typedef enum {
KINC_G4_STENCIL_KEEP,
KINC_G4_STENCIL_ZERO,
KINC_G4_STENCIL_REPLACE,
KINC_G4_STENCIL_INCREMENT,
KINC_G4_STENCIL_INCREMENT_WRAP,
KINC_G4_STENCIL_DECREMENT,
KINC_G4_STENCIL_DECREMENT_WRAP,
KINC_G4_STENCIL_INVERT
} kinc_g4_stencil_action_t;
typedef struct kinc_g4_pipeline {
struct kinc_g4_vertex_structure *input_layout[16];
struct kinc_g4_shader *vertex_shader;
struct kinc_g4_shader *fragment_shader;
struct kinc_g4_shader *geometry_shader;
struct kinc_g4_shader *tessellation_control_shader;
struct kinc_g4_shader *tessellation_evaluation_shader;
kinc_g4_cull_mode_t cull_mode;
bool depth_write;
kinc_g4_compare_mode_t depth_mode;
kinc_g4_compare_mode_t stencil_front_mode;
kinc_g4_stencil_action_t stencil_front_both_pass;
kinc_g4_stencil_action_t stencil_front_depth_fail;
kinc_g4_stencil_action_t stencil_front_fail;
kinc_g4_compare_mode_t stencil_back_mode;
kinc_g4_stencil_action_t stencil_back_both_pass;
kinc_g4_stencil_action_t stencil_back_depth_fail;
kinc_g4_stencil_action_t stencil_back_fail;
int stencil_reference_value;
int stencil_read_mask;
int stencil_write_mask;
// One, Zero deactivates blending
kinc_g4_blending_factor_t blend_source;
kinc_g4_blending_factor_t blend_destination;
kinc_g4_blending_operation_t blend_operation;
kinc_g4_blending_factor_t alpha_blend_source;
kinc_g4_blending_factor_t alpha_blend_destination;
kinc_g4_blending_operation_t alpha_blend_operation;
bool color_write_mask_red[8]; // Per render target
bool color_write_mask_green[8];
bool color_write_mask_blue[8];
bool color_write_mask_alpha[8];
int color_attachment_count;
kinc_g4_render_target_format_t color_attachment[8];
int depth_attachment_bits;
int stencil_attachment_bits;
bool conservative_rasterization;
kinc_g4_pipeline_impl_t impl;
} kinc_g4_pipeline_t;
/// <summary>
/// Initializes a pipeline.
/// </summary>
/// <param name="state">The pipeline to initialize</param>
KINC_FUNC void kinc_g4_pipeline_init(kinc_g4_pipeline_t *pipeline);
/// <summary>
/// Destroys a pipeline.
/// </summary>
/// <param name="pipeline">The pipeline to destroy</param>
KINC_FUNC void kinc_g4_pipeline_destroy(kinc_g4_pipeline_t *pipeline);
/// <summary>
/// Compiles a pipeline. After a pipeline has been compiled it is finalized. It cannot be compiled again and further changes to the pipeline are ignored.
/// </summary>
/// <param name="pipeline">The pipeline to compile</param>
KINC_FUNC void kinc_g4_pipeline_compile(kinc_g4_pipeline_t *pipeline);
#ifndef KINC_KONG
/// <summary>
/// Searches for a constant/uniform and returns a constant-location which can be used to change the constant/uniform.
/// </summary>
/// <param name="pipeline">The pipeline to search in</param>
/// <param name="name">The name of the constant/uniform to find</param>
/// <returns>The constant-location of the constant/uniform</returns>
KINC_FUNC kinc_g4_constant_location_t kinc_g4_pipeline_get_constant_location(kinc_g4_pipeline_t *pipeline, const char *name);
/// <summary>
/// Searches for a texture-declaration and returns a texture-unit which can be used to assign a texture.
/// </summary>
/// <param name="pipeline">The pipeline to search in</param>
/// <param name="name">The name of the texture-declaration to search for</param>
/// <returns>The texture-unit of the texture-declaration</returns>
KINC_FUNC kinc_g4_texture_unit_t kinc_g4_pipeline_get_texture_unit(kinc_g4_pipeline_t *pipeline, const char *name);
#endif
void kinc_g4_internal_set_pipeline(kinc_g4_pipeline_t *pipeline);
void kinc_g4_internal_pipeline_set_defaults(kinc_g4_pipeline_t *pipeline);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,11 @@
#include "rendertarget.h"
void kinc_g4_render_target_init(kinc_g4_render_target_t *renderTarget, int width, int height, kinc_g4_render_target_format_t format, int depthBufferBits,
int stencilBufferBits) {
kinc_g4_render_target_init_with_multisampling(renderTarget, width, height, format, depthBufferBits, stencilBufferBits, 1);
}
void kinc_g4_render_target_init_cube(kinc_g4_render_target_t *renderTarget, int cubeMapSize, kinc_g4_render_target_format_t format, int depthBufferBits,
int stencilBufferBits) {
kinc_g4_render_target_init_cube_with_multisampling(renderTarget, cubeMapSize, format, depthBufferBits, stencilBufferBits, 1);
}

View File

@ -0,0 +1,144 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics4/rendertarget.h>
#include "textureunit.h"
#include <stdint.h>
/*! \file rendertarget.h
\brief Provides functions for handling render-targets.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g4_render_target_format {
KINC_G4_RENDER_TARGET_FORMAT_32BIT,
KINC_G4_RENDER_TARGET_FORMAT_64BIT_FLOAT,
KINC_G4_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT,
KINC_G4_RENDER_TARGET_FORMAT_128BIT_FLOAT,
KINC_G4_RENDER_TARGET_FORMAT_16BIT_DEPTH,
KINC_G4_RENDER_TARGET_FORMAT_8BIT_RED,
KINC_G4_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT
} kinc_g4_render_target_format_t;
typedef struct kinc_g4_render_target {
int width;
int height;
int texWidth;
int texHeight;
bool isCubeMap;
bool isDepthAttachment;
kinc_g4_render_target_impl_t impl;
} kinc_g4_render_target_t;
/// <summary>
/// Allocates and initializes a regular render-target. The contents of the render-target are undefined.
/// </summary>
/// <param name="renderTarget"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
KINC_FUNC void kinc_g4_render_target_init(kinc_g4_render_target_t *renderTarget, int width, int height, kinc_g4_render_target_format_t format,
int depthBufferBits, int stencilBufferBits);
/// <summary>
/// Allocates and initializes a multi-sampled render-target if possible - otherwise it falls back to a regular render-target. The contents of the render-target
/// are undefined.
/// </summary>
/// <param name="renderTarget"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <param name="samples_per_pixel"></param>
KINC_FUNC void kinc_g4_render_target_init_with_multisampling(kinc_g4_render_target_t *renderTarget, int width, int height,
kinc_g4_render_target_format_t format, int depthBufferBits, int stencilBufferBits,
int samples_per_pixel);
/// <summary>
/// Allocates and initializes a render-target-cube-map. The contents of the render-target are undefined.
/// </summary>
/// <param name="renderTarget"></param>
/// <param name="cubeMapSize"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
KINC_FUNC void kinc_g4_render_target_init_cube(kinc_g4_render_target_t *renderTarget, int cubeMapSize, kinc_g4_render_target_format_t format,
int depthBufferBits, int stencilBufferBits);
/// <summary>
/// Allocates and initializes a multi-sampled render-target-cube-map. Can fall back to a non-multi-sampled cube-map. The contents of the render-target are
/// undefined.
/// </summary>
/// <param name="renderTarget"></param>
/// <param name="cubeMapSize"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <param name="samples_per_pixel"></param>
KINC_FUNC void kinc_g4_render_target_init_cube_with_multisampling(kinc_g4_render_target_t *renderTarget, int cubeMapSize, kinc_g4_render_target_format_t format,
int depthBufferBits, int stencilBufferBits, int samples_per_pixel);
/// <summary>
/// Deallocates and destroys a render-target.
/// </summary>
/// <param name="renderTarget">The render-target to destroy</param>
KINC_FUNC void kinc_g4_render_target_destroy(kinc_g4_render_target_t *renderTarget);
#ifdef KINC_KONG
/// <summary>
/// Uses the color-component of a render-target as a texture.
/// </summary>
/// <param name="renderTarget">The render-target to use</param>
/// <param name="unit">The texture-unit to assign the render-target to</param>
KINC_FUNC void kinc_g4_render_target_use_color_as_texture(kinc_g4_render_target_t *renderTarget, uint32_t unit);
#else
/// <summary>
/// Uses the color-component of a render-target as a texture.
/// </summary>
/// <param name="renderTarget">The render-target to use</param>
/// <param name="unit">The texture-unit to assign the render-target to</param>
KINC_FUNC void kinc_g4_render_target_use_color_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit);
#endif
/// <summary>
/// Uses the depth-component of a render-target as a texture.
/// </summary>
/// <param name="renderTarget">The render-target to use</param>
/// <param name="unit">The texture-unit to assign the render-target to</param>
KINC_FUNC void kinc_g4_render_target_use_depth_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit);
/// <summary>
/// Copies the depth and stencil-components of one render-target into another one.
/// </summary>
/// <param name="renderTarget">The render-target to copy the data into</param>
/// <param name="source">The render-target from which to copy the data</param>
/// <returns></returns>
KINC_FUNC void kinc_g4_render_target_set_depth_stencil_from(kinc_g4_render_target_t *renderTarget, kinc_g4_render_target_t *source);
/// <summary>
/// Copies out the color-data from a render-target. Beware, this is very slow.
/// </summary>
/// <param name="renderTarget">The render-target to copy the color-data from</param>
/// <param name="data">A pointer to where the data will be copied to</param>
KINC_FUNC void kinc_g4_render_target_get_pixels(kinc_g4_render_target_t *renderTarget, uint8_t *data);
/// <summary>
/// Generates the mipmap-chain for a render-target.
/// </summary>
/// <param name="renderTarget">The render-target to create the mipmaps for</param>
/// <param name="levels">The number of mipmap-levels to generate</param>
KINC_FUNC void kinc_g4_render_target_generate_mipmaps(kinc_g4_render_target_t *renderTarget, int levels);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,58 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics4/shader.h>
/*! \file shader.h
\brief Provides functions for creating and destroying shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g4_shader_type {
KINC_G4_SHADER_TYPE_FRAGMENT,
KINC_G4_SHADER_TYPE_VERTEX,
KINC_G4_SHADER_TYPE_COMPUTE,
KINC_G4_SHADER_TYPE_GEOMETRY,
KINC_G4_SHADER_TYPE_TESSELLATION_CONTROL,
KINC_G4_SHADER_TYPE_TESSELLATION_EVALUATION,
KINC_G4_SHADER_TYPE_COUNT
} kinc_g4_shader_type_t;
typedef struct kinc_g4_shader {
kinc_g4_shader_impl_t impl;
} kinc_g4_shader_t;
/// <summary>
/// Initializes a shader based on system-specific shader-data. The system-specific shader-data is usually created per system by the krafix-shader-compiler which
/// is automatically called by kincmake.
/// </summary>
/// <param name="shader">The shader to initialize</param>
/// <param name="data">The system-specific shader-data</param>
/// <param name="length">The length of the system-specific shader-data in bytes</param>
/// <param name="type">The type of the shader</param>
KINC_FUNC void kinc_g4_shader_init(kinc_g4_shader_t *shader, const void *data, size_t length, kinc_g4_shader_type_t type);
/// <summary>
/// Initializes a shader from GLSL-source-code. This only works on some platforms and only if KRAFIX_LIBRARY define has been set and the krafix-shader-compiler
/// was compiled in library-mode and linked into the application.
/// </summary>
/// <param name="shader">The shader to initialize</param>
/// <param name="source">The GLSL-shader-source-code</param>
/// <param name="type">The type of the shader</param>
/// <returns>The number of errors the compiler encountered - hopefully it's zero.</returns>
KINC_FUNC int kinc_g4_shader_init_from_source(kinc_g4_shader_t *shader, const char *source, kinc_g4_shader_type_t type);
/// <summary>
/// Destroys a shader.
/// </summary>
/// <param name="shader">The shader to destroy</param>
KINC_FUNC void kinc_g4_shader_destroy(kinc_g4_shader_t *shader);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,106 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics4/texture.h>
#include <kinc/image.h>
/*! \file texture.h
\brief Provides functions for handling textures.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef kinc_image_t kinc_g4_image_t;
typedef struct kinc_g4_texture {
int tex_width;
int tex_height;
int tex_depth;
kinc_image_format_t format;
kinc_g4_texture_impl_t impl;
} kinc_g4_texture_t;
/// <summary>
/// Allocates and initializes a texture without copying any data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="width">The width of the texture to create</param>
/// <param name="height">The height of the texture to create</param>
/// <param name="format">The format of the texture to create</param>
KINC_FUNC void kinc_g4_texture_init(kinc_g4_texture_t *texture, int width, int height, kinc_image_format_t format);
/// <summary>
/// Allocates and initializes a 3d-texture without copying any data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="width">The width of the texture to create</param>
/// <param name="height">The height of the texture to create</param>
/// <param name="depth">The depth of the texture to create</param>
/// <param name="format">The format of the texture to create</param>
KINC_FUNC void kinc_g4_texture_init3d(kinc_g4_texture_t *texture, int width, int height, int depth, kinc_image_format_t format);
/// <summary>
/// Allocates and initializes a texture and copies image-data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="image">The image which's data is copied into the texture</param>
KINC_FUNC void kinc_g4_texture_init_from_image(kinc_g4_texture_t *texture, kinc_image_t *image);
/// <summary>
/// Allocates and initializes a texture and copies image-data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="image">The image which's data is copied into the texture</param>
KINC_FUNC void kinc_g4_texture_init_from_image3d(kinc_g4_texture_t *texture, kinc_image_t *image);
/// <summary>
/// Deallocates and destroys a texture.
/// </summary>
/// <param name="texture">The texture to destroy</param>
KINC_FUNC void kinc_g4_texture_destroy(kinc_g4_texture_t *texture);
KINC_FUNC unsigned char *kinc_g4_texture_lock(kinc_g4_texture_t *texture);
KINC_FUNC void kinc_g4_texture_unlock(kinc_g4_texture_t *texture);
/// <summary>
/// Clears parts of a texture to a color.
/// </summary>
KINC_FUNC void kinc_g4_texture_clear(kinc_g4_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color);
/// <summary>
/// Generates the mipmap-chain for a texture.
/// </summary>
/// <param name="renderTarget">The render-target to create the mipmaps for</param>
/// <param name="levels">The number of mipmap-levels to generate</param>
KINC_FUNC void kinc_g4_texture_generate_mipmaps(kinc_g4_texture_t *texture, int levels);
/// <summary>
/// Sets the mipmap for one level of a texture.
/// </summary>
/// <param name="texture">The texture to set a mipmap-level for</param>
/// <param name="mipmap">The image-data for the mipmap-level to set</param>
/// <param name="level">The mipmap-level to set</param>
KINC_FUNC void kinc_g4_texture_set_mipmap(kinc_g4_texture_t *texture, kinc_image_t *mipmap, int level);
/// <summary>
/// Returns the stride of the first mipmap-layer of the texture in bytes.
/// </summary>
/// <param name="texture">The texture to figure out the stride for</param>
/// <returns>The stride of the first mipmap-layer in bytes</returns>
KINC_FUNC int kinc_g4_texture_stride(kinc_g4_texture_t *texture);
#ifdef KINC_ANDROID
KINC_FUNC void kinc_g4_texture_init_from_id(kinc_g4_texture_t *texture, unsigned texid);
#endif
#if defined(KINC_IOS) || defined(KINC_MACOS)
KINC_FUNC void kinc_g4_texture_upload(kinc_g4_texture_t *texture, uint8_t *data, int stride);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,37 @@
#pragma once
#include <kinc/global.h>
#include "texture.h"
#include <kinc/backend/graphics4/texturearray.h>
/*! \file texturearray.h
\brief Provides functions for creating and destroying texture-arrays.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g4_texture_array {
kinc_g4_texture_array_impl_t impl;
} kinc_g4_texture_array_t;
/// <summary>
/// Allocates and initializes a texture-array based on an array of images.
/// </summary>
/// <param name="array">The texture-array to initialize</param>
/// <param name="images">The images to assign to the texture-array</param>
/// <param name="count">The number of images</param>
KINC_FUNC void kinc_g4_texture_array_init(kinc_g4_texture_array_t *array, kinc_image_t *images, int count);
/// <summary>
/// Deallocates and destroys a texture-array
/// </summary>
/// <param name="array">The texture-array to destroy</param>
KINC_FUNC void kinc_g4_texture_array_destroy(kinc_g4_texture_array_t *array);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,21 @@
#pragma once
#include <kinc/global.h>
#include <kinc/graphics4/shader.h>
/*! \file textureunit.h
\brief Provides a texture-unit-struct which is used for setting textures in a shader.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g4_texture_unit {
int stages[KINC_G4_SHADER_TYPE_COUNT];
} kinc_g4_texture_unit_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,15 @@
#pragma once
/*! \file usage.h
\brief Provides the usage enum.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g4_usage { KINC_G4_USAGE_STATIC, KINC_G4_USAGE_DYNAMIC, KINC_G4_USAGE_READABLE } kinc_g4_usage_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,20 @@
#include "vertexbuffer.h"
static void init_vertex_element(kinc_g4_vertex_element_t *element, const char *name, kinc_g4_vertex_data_t data) {
element->name = name;
element->data = data;
}
void kinc_g4_vertex_structure_init(kinc_g4_vertex_structure_t *structure) {
structure->size = 0;
structure->instanced = false;
}
void kinc_g4_vertex_structure_add(kinc_g4_vertex_structure_t *structure, const char *name, kinc_g4_vertex_data_t data) {
init_vertex_element(&structure->elements[structure->size++], name, data);
}
void kinc_g4_set_vertex_buffer(kinc_g4_vertex_buffer_t *buffer) {
kinc_g4_vertex_buffer_t *buffers[1] = {buffer};
kinc_g4_set_vertex_buffers(buffers, 1);
}

View File

@ -0,0 +1,101 @@
#pragma once
#include <kinc/global.h>
#include "usage.h"
#include "vertexstructure.h"
#include <kinc/backend/graphics4/vertexbuffer.h>
#include <stdbool.h>
/*! \file vertexbuffer.h
\brief Provides functions for setting up and using vertex-buffers.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g4_vertex_buffer {
kinc_g4_vertex_buffer_impl_t impl;
} kinc_g4_vertex_buffer_t;
/// <summary>
/// Allocate and initialize a vertex-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="count">The number of vertices in the buffer</param>
/// <param name="structure">The structure of the buffer</param>
/// <param name="usage">A hint for how the buffer will be used</param>
/// <param name="instance_data_step_rate">The step-rate for instanced-rendering - use 0 if instanced-rendering will not be used with this buffer</param>
KINC_FUNC void kinc_g4_vertex_buffer_init(kinc_g4_vertex_buffer_t *buffer, int count, kinc_g4_vertex_structure_t *structure, kinc_g4_usage_t usage,
int instance_data_step_rate);
/// <summary>
/// Destroys a vertex-buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g4_vertex_buffer_destroy(kinc_g4_vertex_buffer_t *buffer);
/// <summary>
/// Locks all of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the buffer</returns>
KINC_FUNC float *kinc_g4_vertex_buffer_lock_all(kinc_g4_vertex_buffer_t *buffer);
/// <summary>
/// Locks part of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The index of the first vertex to lock</param>
/// <param name="count">The number of vertices to lock</param>
/// <returns>The contents of the buffer, starting at start</returns>
KINC_FUNC float *kinc_g4_vertex_buffer_lock(kinc_g4_vertex_buffer_t *buffer, int start, int count);
/// <summary>
/// Unlock all of a vertex-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g4_vertex_buffer_unlock_all(kinc_g4_vertex_buffer_t *buffer);
/// <summary>
/// Unlocks part of a vertex-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
/// <param name="count">The number of vertices to unlock, starting from the start-vertex from the previous lock-call</param>
KINC_FUNC void kinc_g4_vertex_buffer_unlock(kinc_g4_vertex_buffer_t *buffer, int count);
/// <summary>
/// Returns the number of vertices in a buffer.
/// </summary>
/// <param name="buffer">The buffer to figure out the number of vertices for</param>
/// <returns>The number of vertices</returns>
KINC_FUNC int kinc_g4_vertex_buffer_count(kinc_g4_vertex_buffer_t *buffer);
/// <summary>
/// Returns the stride aka the size of one vertex of the buffer in bytes.
/// </summary>
/// <param name="buffer">The buffer to figure out the stride for</param>
/// <returns>The stride of the buffer in bytes</returns>
KINC_FUNC int kinc_g4_vertex_buffer_stride(kinc_g4_vertex_buffer_t *buffer);
int kinc_internal_g4_vertex_buffer_set(kinc_g4_vertex_buffer_t *buffer, int offset);
/// <summary>
/// Sets vertex-buffers for the next draw-call.
/// </summary>
/// <param name="buffers">The buffers to set</param>
/// <param name="count">The number of buffers to set</param>
KINC_FUNC void kinc_g4_set_vertex_buffers(kinc_g4_vertex_buffer_t **buffers, int count);
/// <summary>
/// Sets a vertex-buffer for the next draw-call.
/// </summary>
/// <param name="buffer">The buffer to set</param>
KINC_FUNC void kinc_g4_set_vertex_buffer(kinc_g4_vertex_buffer_t *buffer);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,157 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
/*! \file vertexstructure.h
\brief Provides functions for setting up the structure of vertices in a vertex-buffer.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g4_vertex_data {
KINC_G4_VERTEX_DATA_NONE = 0,
KINC_G4_VERTEX_DATA_F32_1X = 1,
KINC_G4_VERTEX_DATA_F32_2X = 2,
KINC_G4_VERTEX_DATA_F32_3X = 3,
KINC_G4_VERTEX_DATA_F32_4X = 4,
KINC_G4_VERTEX_DATA_F32_4X4 = 5,
KINC_G4_VERTEX_DATA_I8_1X = 6,
KINC_G4_VERTEX_DATA_U8_1X = 7,
KINC_G4_VERTEX_DATA_I8_1X_NORMALIZED = 8,
KINC_G4_VERTEX_DATA_U8_1X_NORMALIZED = 9,
KINC_G4_VERTEX_DATA_I8_2X = 10,
KINC_G4_VERTEX_DATA_U8_2X = 11,
KINC_G4_VERTEX_DATA_I8_2X_NORMALIZED = 12,
KINC_G4_VERTEX_DATA_U8_2X_NORMALIZED = 13,
KINC_G4_VERTEX_DATA_I8_4X = 14,
KINC_G4_VERTEX_DATA_U8_4X = 15,
KINC_G4_VERTEX_DATA_I8_4X_NORMALIZED = 16,
KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED = 17,
KINC_G4_VERTEX_DATA_I16_1X = 18,
KINC_G4_VERTEX_DATA_U16_1X = 19,
KINC_G4_VERTEX_DATA_I16_1X_NORMALIZED = 20,
KINC_G4_VERTEX_DATA_U16_1X_NORMALIZED = 21,
KINC_G4_VERTEX_DATA_I16_2X = 22,
KINC_G4_VERTEX_DATA_U16_2X = 23,
KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED = 24,
KINC_G4_VERTEX_DATA_U16_2X_NORMALIZED = 25,
KINC_G4_VERTEX_DATA_I16_4X = 26,
KINC_G4_VERTEX_DATA_U16_4X = 27,
KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED = 28,
KINC_G4_VERTEX_DATA_U16_4X_NORMALIZED = 29,
KINC_G4_VERTEX_DATA_I32_1X = 30,
KINC_G4_VERTEX_DATA_U32_1X = 31,
KINC_G4_VERTEX_DATA_I32_2X = 32,
KINC_G4_VERTEX_DATA_U32_2X = 33,
KINC_G4_VERTEX_DATA_I32_3X = 34,
KINC_G4_VERTEX_DATA_U32_3X = 35,
KINC_G4_VERTEX_DATA_I32_4X = 36,
KINC_G4_VERTEX_DATA_U32_4X = 37,
// deprecated
KINC_G4_VERTEX_DATA_FLOAT1 = KINC_G4_VERTEX_DATA_F32_1X,
KINC_G4_VERTEX_DATA_FLOAT2 = KINC_G4_VERTEX_DATA_F32_2X,
KINC_G4_VERTEX_DATA_FLOAT3 = KINC_G4_VERTEX_DATA_F32_3X,
KINC_G4_VERTEX_DATA_FLOAT4 = KINC_G4_VERTEX_DATA_F32_4X,
KINC_G4_VERTEX_DATA_FLOAT4X4 = KINC_G4_VERTEX_DATA_F32_4X4,
KINC_G4_VERTEX_DATA_SHORT2_NORM = KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED,
KINC_G4_VERTEX_DATA_SHORT4_NORM = KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED,
KINC_G4_VERTEX_DATA_COLOR = KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED
} kinc_g4_vertex_data_t;
static inline int kinc_g4_vertex_data_size(kinc_g4_vertex_data_t data) {
switch (data) {
default:
case KINC_G4_VERTEX_DATA_NONE:
return 0;
case KINC_G4_VERTEX_DATA_F32_1X:
return 1 * 4;
case KINC_G4_VERTEX_DATA_F32_2X:
return 2 * 4;
case KINC_G4_VERTEX_DATA_F32_3X:
return 3 * 4;
case KINC_G4_VERTEX_DATA_F32_4X:
return 4 * 4;
case KINC_G4_VERTEX_DATA_F32_4X4:
return 4 * 4 * 4;
case KINC_G4_VERTEX_DATA_I8_1X:
case KINC_G4_VERTEX_DATA_U8_1X:
case KINC_G4_VERTEX_DATA_I8_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U8_1X_NORMALIZED:
return 1 * 1;
case KINC_G4_VERTEX_DATA_I8_2X:
case KINC_G4_VERTEX_DATA_U8_2X:
case KINC_G4_VERTEX_DATA_I8_2X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U8_2X_NORMALIZED:
return 2 * 1;
case KINC_G4_VERTEX_DATA_I8_4X:
case KINC_G4_VERTEX_DATA_U8_4X:
case KINC_G4_VERTEX_DATA_I8_4X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U8_4X_NORMALIZED:
return 4 * 1;
case KINC_G4_VERTEX_DATA_I16_1X:
case KINC_G4_VERTEX_DATA_U16_1X:
case KINC_G4_VERTEX_DATA_I16_1X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U16_1X_NORMALIZED:
return 1 * 2;
case KINC_G4_VERTEX_DATA_I16_2X:
case KINC_G4_VERTEX_DATA_U16_2X:
case KINC_G4_VERTEX_DATA_I16_2X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U16_2X_NORMALIZED:
return 2 * 2;
case KINC_G4_VERTEX_DATA_I16_4X:
case KINC_G4_VERTEX_DATA_U16_4X:
case KINC_G4_VERTEX_DATA_I16_4X_NORMALIZED:
case KINC_G4_VERTEX_DATA_U16_4X_NORMALIZED:
return 4 * 2;
case KINC_G4_VERTEX_DATA_I32_1X:
case KINC_G4_VERTEX_DATA_U32_1X:
return 1 * 4;
case KINC_G4_VERTEX_DATA_I32_2X:
case KINC_G4_VERTEX_DATA_U32_2X:
return 2 * 4;
case KINC_G4_VERTEX_DATA_I32_3X:
case KINC_G4_VERTEX_DATA_U32_3X:
return 3 * 4;
case KINC_G4_VERTEX_DATA_I32_4X:
case KINC_G4_VERTEX_DATA_U32_4X:
return 4 * 4;
}
}
typedef struct kinc_g4_vertex_element {
const char *name;
kinc_g4_vertex_data_t data;
} kinc_g4_vertex_element_t;
#define KINC_G4_MAX_VERTEX_ELEMENTS 16
typedef struct kinc_g4_vertex_structure {
kinc_g4_vertex_element_t elements[KINC_G4_MAX_VERTEX_ELEMENTS];
int size;
bool instanced;
} kinc_g4_vertex_structure_t;
/// <summary>
/// Initializes a vertex-structure.
/// </summary>
/// <param name="structure">The structure to initialize</param>
/// <returns></returns>
KINC_FUNC void kinc_g4_vertex_structure_init(kinc_g4_vertex_structure_t *structure);
/// <summary>
/// Adds an element to a vertex-structure.
/// </summary>
/// <param name="structure">The structure to add an element to</param>
/// <param name="name">The name to use for the new element</param>
/// <param name="data">The type of data to assign for the new element</param>
/// <returns></returns>
KINC_FUNC void kinc_g4_vertex_structure_add(kinc_g4_vertex_structure_t *structure, const char *name, kinc_g4_vertex_data_t data);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1 @@
#include "commandlist.h"

View File

@ -0,0 +1,340 @@
#pragma once
#include <kinc/global.h>
#include "rendertarget.h"
#include "sampler.h"
#include "texture.h"
#include "textureunit.h"
#include <kinc/backend/graphics5/commandlist.h>
#include <stddef.h>
/*! \file commandlist.h
\brief Contains functions for building command-lists to send commands to the GPU.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_G5_CLEAR_COLOR 1
#define KINC_G5_CLEAR_DEPTH 2
#define KINC_G5_CLEAR_STENCIL 4
struct kinc_g5_compute_shader;
struct kinc_g5_constant_buffer;
struct kinc_g5_index_buffer;
struct kinc_g5_pipeline;
struct kinc_g5_render_target;
struct kinc_g5_texture;
struct kinc_g5_vertex_buffer;
struct kinc_g5_render_target;
/*typedef enum kinc_g5_render_target_format {
KINC_G5_RENDER_TARGET_FORMAT_32BIT,
KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_16BIT_DEPTH,
KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED
} kinc_g5_render_target_format_t;*/
// typedef kinc_g4_render_target_format_t kinc_g5_render_target_format_t;
typedef struct kinc_g5_command_list {
CommandList5Impl impl;
} kinc_g5_command_list_t;
/// <summary>
/// Initializes a command-list.
/// </summary>
/// <param name="list">The command-list to initialize</param>
KINC_FUNC void kinc_g5_command_list_init(kinc_g5_command_list_t *list);
/// <summary>
/// Destroys a command-list.
/// </summary>
/// <param name="list">The command-list to destroy</param>
KINC_FUNC void kinc_g5_command_list_destroy(kinc_g5_command_list_t *list);
/// <summary>
/// Starts recording commands in a command-list.
/// </summary>
/// <param name="list">The list to use</param>
KINC_FUNC void kinc_g5_command_list_begin(kinc_g5_command_list_t *list);
/// <summary>
/// Ends recording commands for the list. Has to be called after kinc_g5_command_list_begin and before kinc_g5_command_list_execute.
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_command_list_end(kinc_g5_command_list_t *list);
/// <summary>
/// Records a command to clear the color, depth and/or stencil-components of a render-target.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="render_target">The render-target to clear</param>
/// <param name="flags">Defines what components to clear</param>
/// <param name="color">The color-value to clear to in 0xAARRGGBB</param>
/// <param name="depth">The depth-value to clear to</param>
/// <param name="stencil">The stencil-value to clear to</param>
KINC_FUNC void kinc_g5_command_list_clear(kinc_g5_command_list_t *list, struct kinc_g5_render_target *render_target, unsigned flags, unsigned color,
float depth, int stencil);
/// <summary>
/// Records a command that prepares a render-target to be used as the current framebuffer.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="renderTarget">The render-target to use as the current framebuffer</param>
KINC_FUNC void kinc_g5_command_list_render_target_to_framebuffer_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget);
/// <summary>
/// Records a command that prepares a render-target for regular render-target-usage after being used as the current framebuffer.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="renderTarget">The render-target to use in regular render-target-mode</param>
KINC_FUNC void kinc_g5_command_list_framebuffer_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget);
/// <summary>
/// Writes a command that prepares a render-target to be rendered to.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="renderTarget">The render-target to render to</param>
KINC_FUNC void kinc_g5_command_list_texture_to_render_target_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget);
/// <summary>
/// Writes a command that prepares a render-target to be used for sampling/reading like a texture.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="renderTarget">The render-target to be used like a texture</param>
KINC_FUNC void kinc_g5_command_list_render_target_to_texture_barrier(kinc_g5_command_list_t *list, struct kinc_g5_render_target *renderTarget);
/// <summary>
/// Writes a command that draws the entire content of the currently set index-buffer and vertex-buffer. G4 can only draw triangle-lists using vertex-indices as
/// this is what GPUs tend to be optimized for.
/// </summary>
/// <param name="list">The list to write the command to</param>
KINC_FUNC void kinc_g5_command_list_draw_indexed_vertices(kinc_g5_command_list_t *list);
/// <summary>
/// Writes a command that draws a part of the content of the currently set index-buffer and vertex-buffer. G4 can only draw triangle-lists using vertex-indices
/// as this is what GPUs tend to be optimized for.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="start">The offset into the index-buffer</param>
/// <param name="count">The number of indices to use</param>
KINC_FUNC void kinc_g5_command_list_draw_indexed_vertices_from_to(kinc_g5_command_list_t *list, int start, int count);
/// <summary>
/// Writes a command that draws a part of the content of the currently set index-buffer and vertex-buffer and additionally applies a general offset into the
/// vertex-buffer. G4 can only draw triangle-lists using vertex-indices as this is what GPUs tend to be optimized for.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="start">The offset into the index-buffer</param>
/// <param name="count">The number of indices to use</param>
/// <param name="vertex_offset">The offset into the vertex-buffer which is added to each index read from the index-buffer</param>
KINC_FUNC void kinc_g5_command_list_draw_indexed_vertices_from_to_from(kinc_g5_command_list_t *list, int start, int count, int vertex_offset);
KINC_FUNC void kinc_g5_command_list_draw_indexed_vertices_instanced(kinc_g5_command_list_t *list, int instanceCount);
KINC_FUNC void kinc_g5_command_list_draw_indexed_vertices_instanced_from_to(kinc_g5_command_list_t *list, int instanceCount, int start, int count);
/// <summary>
/// Writes a command that sets the viewport which defines the portion of the framebuffer or render-target things are rendered into. By default the viewport is
/// equivalent to the full size of the current render-target or framebuffer.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="x">The x-offset of the viewport from the left of the screen in pixels</param>
/// <param name="y">The y-offset of the viewport from the top of the screen in pixels</param>
/// <param name="width">The width of the viewport in pixels</param>
/// <param name="height">The height of the viewport in pixels</param>
KINC_FUNC void kinc_g5_command_list_viewport(kinc_g5_command_list_t *list, int x, int y, int width, int height);
/// <summary>
/// Writes a command that enables and defines the scissor-rect. When the scissor-rect is enabled, anything that's rendered outside of the scissor-rect will be
/// ignored.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="x">The x-offset of the scissor-rect from the left of the screen in pixels</param>
/// <param name="y">The y-offset of the scissor-rect from the top of the screen in pixels</param>
/// <param name="width">The width of the scissor-rect in pixels</param>
/// <param name="height">The height of the scissor-rect in pixels</param>
KINC_FUNC void kinc_g5_command_list_scissor(kinc_g5_command_list_t *list, int x, int y, int width, int height);
/// <summary>
/// Writes a command to disable the scissor-rect.
/// </summary>
/// <param name="list">The list to write the command to</param>
KINC_FUNC void kinc_g5_command_list_disable_scissor(kinc_g5_command_list_t *list);
/// <summary>
/// Writes a command to set the pipeline for the next draw-call. The pipeline defines most rendering-state including the shaders to be used.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="pipeline">The pipeline to set</param>
KINC_FUNC void kinc_g5_command_list_set_pipeline(kinc_g5_command_list_t *list, struct kinc_g5_pipeline *pipeline);
/// <summary>
/// Writes a command to set the compute shader for the next compute-call.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="pipeline">The compute shader to set</param>
KINC_FUNC void kinc_g5_command_list_set_compute_shader(kinc_g5_command_list_t *list, struct kinc_g5_compute_shader *shader);
/// <summary>
/// Sets the blend constant used for `KINC_G5_BLEND_CONSTANT` or `KINC_G5_INV_BLEND_CONSTANT`
/// </summary>
KINC_FUNC void kinc_g5_command_list_set_blend_constant(kinc_g5_command_list_t *list, float r, float g, float b, float a);
/// <summary>
/// Writes a command which sets vertex-buffers for the next draw-call.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffers">The buffers to set</param>
/// <param name="offsets">The offset to use for every buffer in number of vertices</param>
/// <param name="count">The number of buffers to set</param>
KINC_FUNC void kinc_g5_command_list_set_vertex_buffers(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer **buffers, int *offsets, int count);
/// <summary>
/// Writes a command to set an index-buffer to be used for the next draw-command.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to use</param>
KINC_FUNC void kinc_g5_command_list_set_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer);
/// <summary>
/// Writes a command that sets the render-targets to draw into in following draw-calls.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="targets">The render-targets to use for following-draw calls</param>
/// <param name="count">The number of render-targets to use</param>
KINC_FUNC void kinc_g5_command_list_set_render_targets(kinc_g5_command_list_t *list, struct kinc_g5_render_target **targets, int count);
/// <summary>
/// Writes a command to upload an index-buffer that's in main-memory to gpu-memory. Does nothing on unified-memory-systems.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to upload</param>
KINC_FUNC void kinc_g5_command_list_upload_index_buffer(kinc_g5_command_list_t *list, struct kinc_g5_index_buffer *buffer);
/// <summary>
/// Writes a command to upload a vertex-buffer that's in main-memory to gpu-memory. Does nothing on unified-memory-systems.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to upload</param>
KINC_FUNC void kinc_g5_command_list_upload_vertex_buffer(kinc_g5_command_list_t *list, struct kinc_g5_vertex_buffer *buffer);
/// <summary>
/// Writes a command to upload a texture that's in main-memory to gpu-memory. Does nothing on unified-memory-systems.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The texture to upload</param>
KINC_FUNC void kinc_g5_command_list_upload_texture(kinc_g5_command_list_t *list, struct kinc_g5_texture *texture);
/// <summary>
/// Writes a command that sets a constant-buffer for the vertex-shader-stage.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to set</param>
/// <param name="offset">The offset into the buffer in bytes to use as the start</param>
/// <param name="size">The size of the buffer to use in bytes starting at the offset</param>
KINC_FUNC void kinc_g5_command_list_set_vertex_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size);
/// <summary>
/// Writes a command that sets a constant-buffer for the fragment-shader-stage.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to set</param>
/// <param name="offset">The offset into the buffer in bytes to use as the start</param>
/// <param name="size">The size of the buffer to use in bytes starting at the offset</param>
KINC_FUNC void kinc_g5_command_list_set_fragment_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size);
/// <summary>
/// Writes a command that sets a constant-buffer for the compute-shader-stage.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="buffer">The buffer to set</param>
/// <param name="offset">The offset into the buffer in bytes to use as the start</param>
/// <param name="size">The size of the buffer to use in bytes starting at the offset</param>
KINC_FUNC void kinc_g5_command_list_set_compute_constant_buffer(kinc_g5_command_list_t *list, struct kinc_g5_constant_buffer *buffer, int offset, size_t size);
/// <summary>
/// Kicks off execution of the commands which have been recorded in the command-list. kinc_g5_command_list_end has to be called beforehand.
/// </summary>
/// <param name="list">The command-list to execute</param>
KINC_FUNC void kinc_g5_command_list_execute(kinc_g5_command_list_t *list);
/// <summary>
/// Waits for execution of the command_list to finish. Make sure the command-list is executing before you wait for it.
/// Also take note that waiting for a command-list to finish executing completely is a very expensive operation.
/// </summary>
/// <param name="list">The command-list to execute</param>
KINC_FUNC void kinc_g5_command_list_wait_for_execution_to_finish(kinc_g5_command_list_t *list);
/// <summary>
/// Writes a command that copies the contents of a render-target into a cpu-side buffer. Beware: This is enormously slow.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="render_target">The render-target to copy the data from</param>
/// <param name="data">The buffer to copy the data into</param>
KINC_FUNC void kinc_g5_command_list_get_render_target_pixels(kinc_g5_command_list_t *list, struct kinc_g5_render_target *render_target, uint8_t *data);
/// <summary>
/// Records a command that fires off a compute-run on x * y * z elements.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="x">The x-size for the compute-run</param>
/// <param name="y">The y-size for the compute-run</param>
/// <param name="z">The z-size for the compute-run</param>
KINC_FUNC void kinc_g5_command_list_compute(kinc_g5_command_list_t *list, int x, int y, int z);
/// <summary>
/// Assigns a texture to a texture-unit for sampled access via GLSL's texture.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="unit">The unit to assign this texture to</param>
/// <param name="texture">The texture to assign to the unit</param>
KINC_FUNC void kinc_g5_command_list_set_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture);
/// <summary>
/// Assigns a texture to a texture-unit for direct access via GLSL's texelFetch (as
/// opposed to GLSL's texture). The name of this functions is unfortunately based
/// on OpenGL's confusing terminology.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="unit">The unit to assign this texture to</param>
/// <param name="texture">The texture to assign to the unit</param>
KINC_FUNC void kinc_g5_command_list_set_image_texture(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_texture_t *texture);
/// <summary>
/// Uses the color-component of a render-target as a texture.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="unit">The texture-unit to assign the render-target to</param>
/// <param name="target">The render-target to use</param>
KINC_FUNC void kinc_g5_command_list_set_texture_from_render_target(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_render_target_t *target);
/// <summary>
/// Uses the depth-component of a render-target as a texture.
/// </summary>
/// <param name="list">The list to write the command to</param>
/// <param name="unit">The texture-unit to assign the render-target to</param>
/// <param name="target">The render-target to use</param>
KINC_FUNC void kinc_g5_command_list_set_texture_from_render_target_depth(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit,
kinc_g5_render_target_t *target);
KINC_FUNC void kinc_g5_command_list_set_render_target_face(kinc_g5_command_list_t *list, kinc_g5_render_target_t *texture, int face);
KINC_FUNC void kinc_g5_command_list_set_sampler(kinc_g5_command_list_t *list, kinc_g5_texture_unit_t unit, kinc_g5_sampler_t *sampler);
// Occlusion Query
KINC_FUNC bool kinc_g5_command_list_init_occlusion_query(kinc_g5_command_list_t *list, unsigned *occlusionQuery);
KINC_FUNC void kinc_g5_command_list_delete_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery);
KINC_FUNC void kinc_g5_command_list_render_occlusion_query(kinc_g5_command_list_t *list, unsigned occlusionQuery, int triangles);
KINC_FUNC bool kinc_g5_command_list_are_query_results_available(kinc_g5_command_list_t *list, unsigned occlusionQuery);
KINC_FUNC void kinc_g5_command_list_get_query_result(kinc_g5_command_list_t *list, unsigned occlusionQuery, unsigned *pixelCount);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,56 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/compute.h>
#include <kinc/graphics5/constantlocation.h>
#include <kinc/graphics5/textureunit.h>
/*! \file compute.h
\brief Provides support for running compute-shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_compute_shader {
kinc_g5_compute_shader_impl impl;
} kinc_g5_compute_shader;
/// <summary>
/// Initialize a compute-shader from system-specific shader-data.
/// </summary>
/// <param name="shader">The shader-object to initialize</param>
/// <param name="source">A pointer to system-specific shader-data</param>
/// <param name="length">Length of the shader-data in bytes</param>
KINC_FUNC void kinc_g5_compute_shader_init(kinc_g5_compute_shader *shader, void *source, int length);
/// <summary>
/// Desotry a shader-object
/// </summary>
/// <param name="shader">The shader-object to destroy</param>
KINC_FUNC void kinc_g5_compute_shader_destroy(kinc_g5_compute_shader *shader);
#ifndef KINC_KONG
/// <summary>
/// Finds the location of a constant/uniform inside of a shader.
/// </summary>
/// <param name="shader">The shader to look into</param>
/// <param name="name">The constant/uniform-name to look for</param>
/// <returns>The found constant-location</returns>
KINC_FUNC kinc_g5_constant_location_t kinc_g5_compute_shader_get_constant_location(kinc_g5_compute_shader *shader, const char *name);
/// <summary>
/// Finds a texture-unit inside of a shader.
/// </summary>
/// <param name="shader">The shader to look into</param>
/// <param name="name">The texture-name to look for</param>
/// <returns>The found texture-unit</returns>
KINC_FUNC kinc_g5_texture_unit_t kinc_g5_compute_shader_get_texture_unit(kinc_g5_compute_shader *shader, const char *name);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,112 @@
#include "constantbuffer.h"
void kinc_g5_constant_buffer_set_int(kinc_g5_constant_buffer_t *buffer, int offset, int value) {
int *ints = (int *)(&buffer->data[offset]);
ints[0] = value;
}
void kinc_g5_constant_buffer_set_int2(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2) {
int *ints = (int *)(&buffer->data[offset]);
ints[0] = value1;
ints[1] = value2;
}
void kinc_g5_constant_buffer_set_int3(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2, int value3) {
int *ints = (int *)(&buffer->data[offset]);
ints[0] = value1;
ints[1] = value2;
ints[2] = value3;
}
void kinc_g5_constant_buffer_set_int4(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2, int value3, int value4) {
int *ints = (int *)(&buffer->data[offset]);
ints[0] = value1;
ints[1] = value2;
ints[2] = value3;
ints[3] = value4;
}
void kinc_g5_constant_buffer_set_ints(kinc_g5_constant_buffer_t *buffer, int offset, int *values, int count) {
int *ints = (int *)(&buffer->data[offset]);
for (int i = 0; i < count; ++i) {
ints[i] = values[i];
}
}
void kinc_g5_constant_buffer_set_float(kinc_g5_constant_buffer_t *buffer, int offset, float value) {
float *floats = (float *)(&buffer->data[offset]);
floats[0] = value;
}
void kinc_g5_constant_buffer_set_float2(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2) {
float *floats = (float *)(&buffer->data[offset]);
floats[0] = value1;
floats[1] = value2;
}
void kinc_g5_constant_buffer_set_float3(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2, float value3) {
float *floats = (float *)(&buffer->data[offset]);
floats[0] = value1;
floats[1] = value2;
floats[2] = value3;
}
void kinc_g5_constant_buffer_set_float4(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2, float value3, float value4) {
float *floats = (float *)(&buffer->data[offset]);
floats[0] = value1;
floats[1] = value2;
floats[2] = value3;
floats[3] = value4;
}
void kinc_g5_constant_buffer_set_floats(kinc_g5_constant_buffer_t *buffer, int offset, float *values, int count) {
float *floats = (float *)(&buffer->data[offset]);
for (int i = 0; i < count; ++i) {
floats[i] = values[i];
}
}
void kinc_g5_constant_buffer_set_bool(kinc_g5_constant_buffer_t *buffer, int offset, bool value) {
int *ints = (int *)(&buffer->data[offset]);
ints[0] = value ? 1 : 0;
}
static void set_matrix3(uint8_t *constants, int offset, kinc_matrix3x3_t *value) {
float *floats = (float *)(&constants[offset]);
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
floats[x + y * 4] = kinc_matrix3x3_get(value, x, y);
}
}
}
void kinc_g5_constant_buffer_set_matrix3(kinc_g5_constant_buffer_t *buffer, int offset, kinc_matrix3x3_t *value) {
if (kinc_g5_transposeMat3) {
kinc_matrix3x3_t m = *value;
kinc_matrix3x3_transpose(&m);
set_matrix3(buffer->data, offset, &m);
}
else {
set_matrix3(buffer->data, offset, value);
}
}
static void set_matrix4(uint8_t *constants, int offset, kinc_matrix4x4_t *value) {
float *floats = (float *)(&constants[offset]);
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
floats[x + y * 4] = kinc_matrix4x4_get(value, x, y);
}
}
}
void kinc_g5_constant_buffer_set_matrix4(kinc_g5_constant_buffer_t *buffer, int offset, kinc_matrix4x4_t *value) {
if (kinc_g5_transposeMat4) {
kinc_matrix4x4_t m = *value;
kinc_matrix4x4_transpose(&m);
set_matrix4(buffer->data, offset, &m);
}
else {
set_matrix4(buffer->data, offset, value);
}
}

View File

@ -0,0 +1,175 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/constantbuffer.h>
#include <kinc/math/matrix.h>
#include <kinc/math/vector.h>
/*! \file constantbuffer.h
\brief Provides support for managing buffers of constant-data for shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_constant_buffer {
uint8_t *data;
ConstantBuffer5Impl impl;
} kinc_g5_constant_buffer_t;
/// <summary>
/// Initializes a constant-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="size">The size of the constant-data in the buffer in bytes</param>
KINC_FUNC void kinc_g5_constant_buffer_init(kinc_g5_constant_buffer_t *buffer, int size);
/// <summary>
/// Destroys a buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g5_constant_buffer_destroy(kinc_g5_constant_buffer_t *buffer);
/// <summary>
/// Locks all of a constant-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the buffer</returns>
KINC_FUNC void kinc_g5_constant_buffer_lock_all(kinc_g5_constant_buffer_t *buffer);
/// <summary>
/// Locks part of a constant-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The offset of where to start the lock in bytes</param>
/// <param name="count">The number of bytes to lock</param>
/// <returns>The contents of the buffer, starting at start</returns>
KINC_FUNC void kinc_g5_constant_buffer_lock(kinc_g5_constant_buffer_t *buffer, int start, int count);
/// <summary>
/// Unlocks a constant-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g5_constant_buffer_unlock(kinc_g5_constant_buffer_t *buffer);
/// <summary>
/// Figures out the size of the constant-data in the buffer.
/// </summary>
/// <param name="buffer">The buffer to figure out the size for</param>
/// <returns>Returns the size of the constant-data in the buffer in bytes</returns>
KINC_FUNC int kinc_g5_constant_buffer_size(kinc_g5_constant_buffer_t *buffer);
/// <summary>
/// Assigns a bool at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value">The value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_bool(kinc_g5_constant_buffer_t *buffer, int offset, bool value);
/// <summary>
/// Assigns an integer at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value">The value to assign to the constant/uniform</param>
KINC_FUNC void kinc_g5_constant_buffer_set_int(kinc_g5_constant_buffer_t *buffer, int offset, int value);
/// <summary>
/// Assigns two integers at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_int2(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2);
/// <summary>
/// Assigns three integers at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
/// <param name="value3">The third value to write into the buffer/param>
KINC_FUNC void kinc_g5_constant_buffer_set_int3(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2, int value3);
/// <summary>
/// Assigns four integers at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
/// <param name="value3">The third value to write into the buffer/param>
/// <param name="value4">The fourth value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_int4(kinc_g5_constant_buffer_t *buffer, int offset, int value1, int value2, int value3, int value4);
/// <summary>
/// Assigns a bunch of integers at an offset in a constant-buffer.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value">The values to write into the buffer</param>
/// <param name="value">The number of values to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_ints(kinc_g5_constant_buffer_t *buffer, int offset, int *values, int count);
/// <summary>
/// Assigns a float at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value">The value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_float(kinc_g5_constant_buffer_t *buffer, int offset, float value);
/// <summary>
/// Assigns two floats at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_float2(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2);
/// <summary>
/// Assigns three floats at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
/// <param name="value3">The third value to write into the buffer/param>
KINC_FUNC void kinc_g5_constant_buffer_set_float3(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2, float value3);
/// <summary>
/// Assigns four floats at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value1">The first value to write into the buffer</param>
/// <param name="value2">The second value to write into the buffer</param>
/// <param name="value3">The third value to write into the buffer/param>
/// <param name="value4">The fourth value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_float4(kinc_g5_constant_buffer_t *buffer, int offset, float value1, float value2, float value3, float value4);
/// <summary>
/// Assigns a bunch of floats at an offset in a constant-buffer.
/// </summary>
/// <param name="location">The location of the constant/uniform to assign the values to</param>
/// <param name="value">The values to write into the buffer</param>
/// <param name="value">The number of values to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_floats(kinc_g5_constant_buffer_t *buffer, int offset, float *values, int count);
/// <summary>
/// Assigns a 3x3-matrix at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value">The value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_matrix3(kinc_g5_constant_buffer_t *buffer, int offset, kinc_matrix3x3_t *value);
/// <summary>
/// Assigns a 4x4-matrix at an offset in a constant-buffer.
/// </summary>
/// <param name="offset">The offset at which to write the data</param>
/// <param name="value">The value to write into the buffer</param>
KINC_FUNC void kinc_g5_constant_buffer_set_matrix4(kinc_g5_constant_buffer_t *buffer, int offset, kinc_matrix4x4_t *value);
KINC_FUNC extern bool kinc_g5_transposeMat3;
KINC_FUNC extern bool kinc_g5_transposeMat4;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,21 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/pipeline.h>
/*! \file constantlocation.h
\brief Provides the constant_location-struct which is used for setting constants/uniforms in a shader.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_constant_location {
ConstantLocation5Impl impl;
} kinc_g5_constant_location_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
#include "commandlist.c.h"
#include "constantbuffer.c.h"
#include "graphics.c.h"
#include "pipeline.c.h"
#include "rendertarget.c.h"
#include "sampler.c.h"
#include "texture.c.h"

View File

@ -0,0 +1,22 @@
#ifndef OPENGL_1_X
#include "graphics.h"
static int samples = 1;
int kinc_g5_antialiasing_samples(void) {
return samples;
}
void kinc_g5_set_antialiasing_samples(int samples_) {
samples = samples_;
}
bool kinc_g5_fullscreen = false;
// void Graphics5::setVertexBuffer(VertexBuffer& vertexBuffer) {
// VertexBuffer* vertexBuffers[1] = {&vertexBuffer};
// setVertexBuffers(vertexBuffers, 1);
//}
#endif

View File

@ -0,0 +1,113 @@
#pragma once
#include <kinc/global.h>
#include <kinc/image.h>
#include "rendertarget.h"
#include "shader.h"
#include "vertexstructure.h"
#include <kinc/backend/graphics5/graphics.h>
#include <kinc/math/matrix.h>
#include <kinc/math/vector.h>
/*! \file graphics.h
\brief Contains the base G5-functionality.
*/
#ifdef __cplusplus
extern "C" {
#endif
KINC_FUNC extern bool kinc_g5_fullscreen;
/// <summary>
/// Returns whether raytracing (see kinc/graphics5/raytrace.h) is supported.
/// </summary>
/// <returns>Whether raytracing is supported</returns>
KINC_FUNC bool kinc_g5_supports_raytracing(void);
/// <summary>
/// Returns whether instanced rendering (kinc_g5_command_list_draw_indexed_vertices_instanced and pals) is supported.
/// </summary>
/// <returns>Whether instanced rendering is supported</returns>
KINC_FUNC bool kinc_g5_supports_instanced_rendering(void);
/// <summary>
/// Returns whether GPU-compute (the functions in kinc/compute/compute.h) is supported.
/// </summary>
/// <returns>Whether GPU-compute is supported</returns>
KINC_FUNC bool kinc_g5_supports_compute_shaders(void);
/// <summary>
/// Returns whether blend-constants (see kinc_g4_set_blend_constant and the blending-properties for pipelines) are supported.
/// </summary>
/// <returns>Whether blend-constants are supported</returns>
KINC_FUNC bool kinc_g5_supports_blend_constants(void);
/// <summary>
/// Returns whether textures are supported which have widths/heights which are not powers of two.
/// </summary>
/// <returns>Whether non power of two texture-sizes are supported</returns>
KINC_FUNC bool kinc_g5_supports_non_pow2_textures(void);
/// <summary>
/// Returns whether render-targets are upside down. This happens in OpenGL and there is currently no automatic mitigation.
/// </summary>
/// <returns>Whether render-targets are upside down</returns>
KINC_FUNC bool kinc_g5_render_targets_inverted_y(void);
/// <summary>
/// Returns how many textures can be used at the same time in a fragment-shader.
/// </summary>
/// <returns>The number of textures</returns>
KINC_FUNC int kinc_g5_max_bound_textures(void);
/// <summary>
/// I think this does nothing.
/// </summary>
KINC_FUNC void kinc_g5_flush(void);
/// <summary>
/// Returns the currently used number of samples for hardware-antialiasing.
/// </summary>
/// <returns>The number of samples</returns>
KINC_FUNC int kinc_g5_antialiasing_samples(void);
/// <summary>
/// Sets the number of samples used for hardware-antialiasing. This typically uses multisampling and typically only works with a few specific numbers of
/// sample-counts - 2 and 4 are pretty safe bets. It also might do nothing at all.
/// </summary>
/// <param name="samples">The number of samples</param>
KINC_FUNC void kinc_g5_set_antialiasing_samples(int samples);
/// <summary>
/// Needs to be called before rendering to a window. Typically called at the start of each frame.
/// </summary>
/// <param name="window">The window to render to</param>
KINC_FUNC void kinc_g5_begin(kinc_g5_render_target_t *renderTarget, int window);
/// <summary>
/// Needs to be called after rendering to a window. Typically called at the end of each frame.
/// </summary>
/// <param name="window">The window to render to</param>
/// <returns></returns>
KINC_FUNC void kinc_g5_end(int window);
/// <summary>
/// Needs to be called to make the rendered frame visible. Typically called at the very end of each frame.
/// </summary>
KINC_FUNC bool kinc_g5_swap_buffers(void);
#ifndef KINC_DOCS
void kinc_g5_internal_init(void);
void kinc_g5_internal_init_window(int window, int depth_buffer_bits, int stencil_buffer_bits, bool vsync);
void kinc_g5_internal_destroy_window(int window);
void kinc_g5_internal_destroy(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,73 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/indexbuffer.h>
/*! \file indexbuffer.h
\brief Provides functions for setting up and using index-buffers.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g5_index_buffer_format { KINC_G5_INDEX_BUFFER_FORMAT_32BIT, KINC_G5_INDEX_BUFFER_FORMAT_16BIT } kinc_g5_index_buffer_format_t;
typedef struct kinc_g5_index_buffer {
IndexBuffer5Impl impl;
} kinc_g5_index_buffer_t;
/// <summary>
/// Initializes an index-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="count">The number of indices to allocate for the buffer</param>
/// <param name="gpu_memory">When true, the buffer will be uploaded to gpu-memory which will make it faster to use but slower to change</param>
KINC_FUNC void kinc_g5_index_buffer_init(kinc_g5_index_buffer_t *buffer, int count, kinc_g5_index_buffer_format_t format, bool gpu_memory);
/// <summary>
/// Destroys an index-buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g5_index_buffer_destroy(kinc_g5_index_buffer_t *buffer);
/// <summary>
/// Locks an index-buffer so its contents can be modified.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the index-buffer in uint32s or uint16s depending on the format provided when initializing</returns>
KINC_FUNC void *kinc_g5_index_buffer_lock_all(kinc_g5_index_buffer_t *buffer);
/// <summary>
/// Locks part of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The index of the first index to lock</param>
/// <param name="count">The number of indices to lock</param>
/// <returns>The contents of the index-buffer, starting at start, in uint32s or uint16s depending on the format provided when initializing</returns>
KINC_FUNC void *kinc_g5_index_buffer_lock(kinc_g5_index_buffer_t *buffer, int start, int count);
/// <summary>
/// Unlocks an index-buffer after locking it so the changed buffer-contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g5_index_buffer_unlock_all(kinc_g5_index_buffer_t *buffer);
/// <summary>
/// Unlocks part of an index-buffer after locking so the changed buffer-contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
/// <param name="count">The number of indices to unlock, starting from the start-index from the previous lock-call</param>
KINC_FUNC void kinc_g5_index_buffer_unlock(kinc_g5_index_buffer_t *buffer, int count);
/// <summary>
/// Returns the number of indices in the buffer.
/// </summary>
/// <param name="buffer">The buffer to query for its number of indices</param>
/// <returns>The number of indices</returns>
KINC_FUNC int kinc_g5_index_buffer_count(kinc_g5_index_buffer_t *buffer);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,47 @@
#include "pipeline.h"
void kinc_g5_internal_pipeline_init(kinc_g5_pipeline_t *pipe) {
for (int i = 0; i < 16; ++i)
pipe->inputLayout[i] = NULL;
pipe->vertexShader = NULL;
pipe->fragmentShader = NULL;
pipe->geometryShader = NULL;
pipe->tessellationControlShader = NULL;
pipe->tessellationEvaluationShader = NULL;
pipe->cullMode = KINC_G5_CULL_MODE_NEVER;
pipe->depthWrite = false;
pipe->depthMode = KINC_G5_COMPARE_MODE_ALWAYS;
pipe->stencilMode = KINC_G5_COMPARE_MODE_ALWAYS;
pipe->stencilBothPass = KINC_G5_STENCIL_ACTION_KEEP;
pipe->stencilDepthFail = KINC_G5_STENCIL_ACTION_KEEP;
pipe->stencilFail = KINC_G5_STENCIL_ACTION_KEEP;
pipe->stencilReferenceValue = 0;
pipe->stencilReadMask = 0xff;
pipe->stencilWriteMask = 0xff;
pipe->blend_source = KINC_G5_BLEND_ONE;
pipe->blend_destination = KINC_G5_BLEND_ZERO;
pipe->blend_operation = KINC_G5_BLENDOP_ADD;
pipe->alpha_blend_source = KINC_G5_BLEND_ONE;
pipe->alpha_blend_destination = KINC_G5_BLEND_ZERO;
pipe->alpha_blend_operation = KINC_G5_BLENDOP_ADD;
for (int i = 0; i < 8; ++i)
pipe->colorWriteMaskRed[i] = true;
for (int i = 0; i < 8; ++i)
pipe->colorWriteMaskGreen[i] = true;
for (int i = 0; i < 8; ++i)
pipe->colorWriteMaskBlue[i] = true;
for (int i = 0; i < 8; ++i)
pipe->colorWriteMaskAlpha[i] = true;
pipe->colorAttachmentCount = 1;
for (int i = 0; i < 8; ++i)
pipe->colorAttachment[i] = KINC_G5_RENDER_TARGET_FORMAT_32BIT;
pipe->depthAttachmentBits = 0;
pipe->stencilAttachmentBits = 0;
}

View File

@ -0,0 +1,156 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/pipeline.h>
#include <kinc/graphics5/vertexstructure.h>
#include "constantlocation.h"
#include "graphics.h"
/*! \file pipeline.h
\brief Provides functions for creating and using pipelines which configure the GPU for rendering.
*/
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_g5_shader;
// identical to kinc_g4_blending_factor_t
typedef enum {
KINC_G5_BLEND_ONE,
KINC_G5_BLEND_ZERO,
KINC_G5_BLEND_SOURCE_ALPHA,
KINC_G5_BLEND_DEST_ALPHA,
KINC_G5_BLEND_INV_SOURCE_ALPHA,
KINC_G5_BLEND_INV_DEST_ALPHA,
KINC_G5_BLEND_SOURCE_COLOR,
KINC_G5_BLEND_DEST_COLOR,
KINC_G5_BLEND_INV_SOURCE_COLOR,
KINC_G5_BLEND_INV_DEST_COLOR,
KINC_G5_BLEND_CONSTANT,
KINC_G5_BLEND_INV_CONSTANT
} kinc_g5_blending_factor_t;
// identical to kinc_g4_blending_operation_t
typedef enum {
KINC_G5_BLENDOP_ADD,
KINC_G5_BLENDOP_SUBTRACT,
KINC_G5_BLENDOP_REVERSE_SUBTRACT,
KINC_G5_BLENDOP_MIN,
KINC_G5_BLENDOP_MAX
} kinc_g5_blending_operation_t;
typedef enum kinc_g5_cull_mode { KINC_G5_CULL_MODE_CLOCKWISE, KINC_G5_CULL_MODE_COUNTERCLOCKWISE, KINC_G5_CULL_MODE_NEVER } kinc_g5_cull_mode_t;
typedef enum kinc_g5_compare_mode {
KINC_G5_COMPARE_MODE_ALWAYS,
KINC_G5_COMPARE_MODE_NEVER,
KINC_G5_COMPARE_MODE_EQUAL,
KINC_G5_COMPARE_MODE_NOT_EQUAL,
KINC_G5_COMPARE_MODE_LESS,
KINC_G5_COMPARE_MODE_LESS_EQUAL,
KINC_G5_COMPARE_MODE_GREATER,
KINC_G5_COMPARE_MODE_GREATER_EQUAL
} kinc_g5_compare_mode_t;
typedef enum kinc_g5_stencil_action {
KINC_G5_STENCIL_ACTION_KEEP,
KINC_G5_STENCIL_ACTION_ZERO,
KINC_G5_STENCIL_ACTION_REPLACE,
KINC_G5_STENCIL_ACTION_INCREMENT,
KINC_G5_STENCIL_ACTION_INCREMENT_WRAP,
KINC_G5_STENCIL_ACTION_DECREMENT,
KINC_G5_STENCIL_ACTION_DECREMENT_WRAP,
KINC_G5_STENCIL_ACTION_INVERT
} kinc_g5_stencil_action_t;
typedef struct kinc_g5_pipeline {
kinc_g5_vertex_structure_t *inputLayout[16];
struct kinc_g5_shader *vertexShader;
struct kinc_g5_shader *fragmentShader;
struct kinc_g5_shader *geometryShader;
struct kinc_g5_shader *tessellationControlShader;
struct kinc_g5_shader *tessellationEvaluationShader;
kinc_g5_cull_mode_t cullMode;
bool depthWrite;
kinc_g5_compare_mode_t depthMode;
kinc_g5_compare_mode_t stencilMode;
kinc_g5_stencil_action_t stencilBothPass;
kinc_g5_stencil_action_t stencilDepthFail;
kinc_g5_stencil_action_t stencilFail;
int stencilReferenceValue;
int stencilReadMask;
int stencilWriteMask;
// One, Zero deactivates blending
kinc_g5_blending_factor_t blend_source;
kinc_g5_blending_factor_t blend_destination;
kinc_g5_blending_operation_t blend_operation;
kinc_g5_blending_factor_t alpha_blend_source;
kinc_g5_blending_factor_t alpha_blend_destination;
kinc_g5_blending_operation_t alpha_blend_operation;
bool colorWriteMaskRed[8]; // Per render target
bool colorWriteMaskGreen[8];
bool colorWriteMaskBlue[8];
bool colorWriteMaskAlpha[8];
int colorAttachmentCount;
kinc_g5_render_target_format_t colorAttachment[8];
int depthAttachmentBits;
int stencilAttachmentBits;
bool conservativeRasterization;
PipelineState5Impl impl;
} kinc_g5_pipeline_t;
/// <summary>
/// Initializes a pipeline.
/// </summary>
/// <param name="state">The pipeline to initialize</param>
KINC_FUNC void kinc_g5_pipeline_init(kinc_g5_pipeline_t *pipeline);
void kinc_g5_internal_pipeline_init(kinc_g5_pipeline_t *pipeline);
/// <summary>
/// Destroys a pipeline.
/// </summary>
/// <param name="pipeline">The pipeline to destroy</param>
KINC_FUNC void kinc_g5_pipeline_destroy(kinc_g5_pipeline_t *pipeline);
/// <summary>
/// Compiles a pipeline. After a pipeline has been compiled it is finalized. It cannot be compiled again and further changes to the pipeline are ignored.
/// </summary>
/// <param name="pipeline">The pipeline to compile</param>
KINC_FUNC void kinc_g5_pipeline_compile(kinc_g5_pipeline_t *pipeline);
#ifndef KINC_KONG
/// <summary>
/// Searches for a constant/uniform and returns a constant-location which can be used to change the constant/uniform.
/// </summary>
/// <param name="pipeline">The pipeline to search in</param>
/// <param name="name">The name of the constant/uniform to find</param>
/// <returns>The constant-location of the constant/uniform</returns>
KINC_FUNC kinc_g5_constant_location_t kinc_g5_pipeline_get_constant_location(kinc_g5_pipeline_t *pipeline, const char *name);
/// <summary>
/// Searches for a texture-declaration and returns a texture-unit which can be used to assign a texture.
/// </summary>
/// <param name="pipeline">The pipeline to search in</param>
/// <param name="name">The name of the texture-declaration to search for</param>
/// <returns>The texture-unit of the texture-declaration</returns>
KINC_FUNC kinc_g5_texture_unit_t kinc_g5_pipeline_get_texture_unit(kinc_g5_pipeline_t *pipeline, const char *name);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,49 @@
#pragma once
/*! \file raytrace.h
\brief Preliminary API, requires some actual D3D12/Vulkan code to fill in
the acceleration-structure and pipeline-details. Also requires manually
compiled shaders. Use with caution.
*/
#include <kinc/global.h>
#include <kinc/backend/graphics5/raytrace.h>
#ifdef __cplusplus
extern "C" {
#endif
struct kinc_g5_command_list;
struct kinc_g5_constant_buffer;
struct kinc_g5_index_buffer;
struct kinc_g5_render_target;
struct kinc_g5_texture;
struct kinc_g5_vertex_buffer;
typedef struct kinc_raytrace_pipeline {
struct kinc_g5_constant_buffer *_constant_buffer;
kinc_raytrace_pipeline_impl_t impl;
} kinc_raytrace_pipeline_t;
KINC_FUNC void kinc_raytrace_pipeline_init(kinc_raytrace_pipeline_t *pipeline, struct kinc_g5_command_list *command_list, void *ray_shader, int ray_shader_size,
struct kinc_g5_constant_buffer *constant_buffer);
KINC_FUNC void kinc_raytrace_pipeline_destroy(kinc_raytrace_pipeline_t *pipeline);
typedef struct kinc_raytrace_acceleration_structure {
kinc_raytrace_acceleration_structure_impl_t impl;
} kinc_raytrace_acceleration_structure_t;
KINC_FUNC void kinc_raytrace_acceleration_structure_init(kinc_raytrace_acceleration_structure_t *accel, struct kinc_g5_command_list *command_list,
struct kinc_g5_vertex_buffer *vb, struct kinc_g5_index_buffer *ib);
KINC_FUNC void kinc_raytrace_acceleration_structure_destroy(kinc_raytrace_acceleration_structure_t *accel);
KINC_FUNC void kinc_raytrace_set_acceleration_structure(kinc_raytrace_acceleration_structure_t *accel);
KINC_FUNC void kinc_raytrace_set_pipeline(kinc_raytrace_pipeline_t *pipeline);
KINC_FUNC void kinc_raytrace_set_target(struct kinc_g5_texture *output);
KINC_FUNC void kinc_raytrace_dispatch_rays(struct kinc_g5_command_list *command_list);
KINC_FUNC void kinc_raytrace_copy(struct kinc_g5_command_list *command_list, struct kinc_g5_render_target *target, struct kinc_g5_texture *source);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,16 @@
#include "rendertarget.h"
void kinc_g5_render_target_init(kinc_g5_render_target_t *render_target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits,
int stencilBufferBits) {
kinc_g5_render_target_init_with_multisampling(render_target, width, height, format, depthBufferBits, stencilBufferBits, 1);
}
void kinc_g5_render_target_init_framebuffer(kinc_g5_render_target_t *render_target, int width, int height, kinc_g5_render_target_format_t format,
int depthBufferBits, int stencilBufferBits) {
kinc_g5_render_target_init_framebuffer_with_multisampling(render_target, width, height, format, depthBufferBits, stencilBufferBits, 1);
}
void kinc_g5_render_target_init_cube(kinc_g5_render_target_t *render_target, int cubeMapSize, kinc_g5_render_target_format_t format, int depthBufferBits,
int stencilBufferBits) {
kinc_g5_render_target_init_cube_with_multisampling(render_target, cubeMapSize, format, depthBufferBits, stencilBufferBits, 1);
}

View File

@ -0,0 +1,134 @@
#pragma once
#include <kinc/global.h>
#include "textureunit.h"
#include <kinc/backend/graphics5/rendertarget.h>
/*! \file rendertarget.h
\brief Provides functions for handling render-targets.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g5_render_target_format {
KINC_G5_RENDER_TARGET_FORMAT_32BIT,
KINC_G5_RENDER_TARGET_FORMAT_64BIT_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_32BIT_RED_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_128BIT_FLOAT,
KINC_G5_RENDER_TARGET_FORMAT_16BIT_DEPTH,
KINC_G5_RENDER_TARGET_FORMAT_8BIT_RED,
KINC_G5_RENDER_TARGET_FORMAT_16BIT_RED_FLOAT
} kinc_g5_render_target_format_t;
typedef struct kinc_g5_render_target {
int width;
int height;
int texWidth;
int texHeight;
int framebuffer_index;
bool isCubeMap;
bool isDepthAttachment;
RenderTarget5Impl impl;
} kinc_g5_render_target_t;
/// <summary>
/// Allocates and initializes a regular render-target. The contents of the render-target are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format, int depthBufferBits,
int stencilBufferBits);
/// <summary>
/// Allocates and initializes a regular render-target. Can fall back to a regular render-target. The contents of the render-target are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <param name="samples_per_pixel"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init_with_multisampling(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format,
int depthBufferBits, int stencilBufferBits, int samples_per_pixel);
/// <summary>
/// Allocates and initializes a framebuffer. The contents of the framebuffer are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init_framebuffer(kinc_g5_render_target_t *target, int width, int height, kinc_g5_render_target_format_t format,
int depthBufferBits, int stencilBufferBits);
/// <summary>
/// Allocates and initializes a multisampled framebuffer. Can fall back to a regular framebuffer. The contents of the framebuffer are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <param name="samples_per_pixel"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init_framebuffer_with_multisampling(kinc_g5_render_target_t *target, int width, int height,
kinc_g5_render_target_format_t format, int depthBufferBits, int stencilBufferBits,
int samples_per_pixel);
/// <summary>
/// Allocates and initializes a render-target-cube-map. The contents of the render-target are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="cubeMapSize"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init_cube(kinc_g5_render_target_t *target, int cubeMapSize, kinc_g5_render_target_format_t format, int depthBufferBits,
int stencilBufferBits);
/// <summary>
/// Allocates and initializes a multisampled render-target-cube-map. Can fall back to a regular cube-map. The contents of the render-target are undefined.
/// </summary>
/// <param name="target"></param>
/// <param name="cubeMapSize"></param>
/// <param name="format"></param>
/// <param name="depthBufferBits"></param>
/// <param name="stencilBufferBits"></param>
/// <param name="samples_per_pixel"></param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_init_cube_with_multisampling(kinc_g5_render_target_t *target, int cubeMapSize, kinc_g5_render_target_format_t format,
int depthBufferBits, int stencilBufferBits, int samples_per_pixel);
/// <summary>
/// Deallocates and destroys a render-target.
/// </summary>
/// <param name="renderTarget">The render-target to destroy</param>
KINC_FUNC void kinc_g5_render_target_destroy(kinc_g5_render_target_t *target);
/// <summary>
/// Copies the depth and stencil-components of one render-target into another one.
/// </summary>
/// <param name="renderTarget">The render-target to copy the data into</param>
/// <param name="source">The render-target from which to copy the data</param>
/// <returns></returns>
KINC_FUNC void kinc_g5_render_target_set_depth_stencil_from(kinc_g5_render_target_t *target, kinc_g5_render_target_t *source);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,19 @@
#include "sampler.h"
void kinc_g5_sampler_options_set_defaults(kinc_g5_sampler_options_t *options) {
options->u_addressing = KINC_G5_TEXTURE_ADDRESSING_CLAMP;
options->v_addressing = KINC_G5_TEXTURE_ADDRESSING_CLAMP;
options->w_addressing = KINC_G5_TEXTURE_ADDRESSING_CLAMP;
options->magnification_filter = KINC_G5_TEXTURE_FILTER_POINT;
options->minification_filter = KINC_G5_TEXTURE_FILTER_POINT;
options->mipmap_filter = KINC_G5_MIPMAP_FILTER_POINT;
options->lod_min_clamp = 0.0f;
options->lod_max_clamp = 32.0f;
options->is_comparison = false;
options->compare_mode = KINC_G5_COMPARE_MODE_ALWAYS;
options->max_anisotropy = 1;
}

View File

@ -0,0 +1,78 @@
#pragma once
#include <kinc/backend/graphics5/sampler.h>
#include <kinc/graphics5/pipeline.h>
/*! \file sampler.h
\brief Provides functions for sampler objects.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g5_texture_addressing {
KINC_G5_TEXTURE_ADDRESSING_REPEAT,
KINC_G5_TEXTURE_ADDRESSING_MIRROR,
KINC_G5_TEXTURE_ADDRESSING_CLAMP,
KINC_G5_TEXTURE_ADDRESSING_BORDER
} kinc_g5_texture_addressing_t;
typedef enum kinc_g5_texture_filter {
KINC_G5_TEXTURE_FILTER_POINT,
KINC_G5_TEXTURE_FILTER_LINEAR,
KINC_G5_TEXTURE_FILTER_ANISOTROPIC
} kinc_g5_texture_filter_t;
typedef enum kinc_g5_mipmap_filter {
KINC_G5_MIPMAP_FILTER_NONE,
KINC_G5_MIPMAP_FILTER_POINT,
KINC_G5_MIPMAP_FILTER_LINEAR // linear texture filter + linear mip filter -> trilinear filter
} kinc_g5_mipmap_filter_t;
typedef struct kinc_g5_sampler_options {
kinc_g5_texture_addressing_t u_addressing;
kinc_g5_texture_addressing_t v_addressing;
kinc_g5_texture_addressing_t w_addressing;
kinc_g5_texture_filter_t minification_filter;
kinc_g5_texture_filter_t magnification_filter;
kinc_g5_mipmap_filter_t mipmap_filter;
float lod_min_clamp;
float lod_max_clamp;
uint16_t max_anisotropy;
bool is_comparison;
kinc_g5_compare_mode_t compare_mode;
} kinc_g5_sampler_options_t;
typedef struct kinc_g5_sampler {
kinc_g5_sampler_impl_t impl;
} kinc_g5_sampler_t;
/// <summary>
/// Initializes the passed options-object with the default-options.
/// </summary>
/// <param name="options">The options-object for which the default-options will be set</param>
KINC_FUNC void kinc_g5_sampler_options_set_defaults(kinc_g5_sampler_options_t *options);
/// <summary>
/// Creates a sampler-object.
///
/// On platforms such as older OpenGL not all sampler attributes may be available.
/// </summary>
/// <param name="sampler">Pointer to the sampler object to initialize</param>
/// <param name="descriptor">Options for the sampler</param>
KINC_FUNC void kinc_g5_sampler_init(kinc_g5_sampler_t *sampler, const kinc_g5_sampler_options_t *options);
/// <summary>
/// Destroys a sampler-object.
/// </summary>
/// <param name="sampler">The sampler-object to destroy</param>
KINC_FUNC void kinc_g5_sampler_destroy(kinc_g5_sampler_t *sampler);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,50 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/shader.h>
#include <stddef.h>
/*! \file shader.h
\brief Provides functions for creating and destroying shaders.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_g5_shader_type {
KINC_G5_SHADER_TYPE_FRAGMENT,
KINC_G5_SHADER_TYPE_VERTEX,
KINC_G5_SHADER_TYPE_COMPUTE,
KINC_G5_SHADER_TYPE_GEOMETRY,
KINC_G5_SHADER_TYPE_TESSELLATION_CONTROL,
KINC_G5_SHADER_TYPE_TESSELLATION_EVALUATION,
KINC_G5_SHADER_TYPE_COUNT
} kinc_g5_shader_type_t;
typedef struct kinc_g5_shader {
Shader5Impl impl;
} kinc_g5_shader_t;
/// <summary>
/// Initializes a shader based on system-specific shader-data. The system-specific shader-data is usually created per system by the krafix-shader-compiler which
/// is automatically called by kincmake.
/// </summary>
/// <param name="shader">The shader to initialize</param>
/// <param name="data">The system-specific shader-data</param>
/// <param name="length">The length of the system-specific shader-data in bytes</param>
/// <param name="type">The type of the shader</param>
KINC_FUNC void kinc_g5_shader_init(kinc_g5_shader_t *shader, const void *source, size_t length, kinc_g5_shader_type_t type);
/// <summary>
/// Destroys a shader.
/// </summary>
/// <param name="shader">The shader to destroy</param>
KINC_FUNC void kinc_g5_shader_destroy(kinc_g5_shader_t *shader);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,32 @@
#include "texture.h"
/*
Graphics5::Texture::Texture(Kore::Reader& reader, const char* format, bool readable) : Image(reader, format, readable) {
_init(format, readable);
}
Graphics5::Texture::Texture(const char* filename, bool readable) {
FileReader reader(filename);
Image::init(reader, filename, readable);
_init(filename, readable);
}
Graphics5::Texture::Texture(void* data, int size, const char* format, bool readable) {
BufferReader reader(data, size);
Image::init(reader, format, readable);
_init(format, readable);
}
Graphics5::Texture::Texture(void* data, int width, int height, int format, bool readable) : Image(data, width, height, Image::Format(format), readable) {
_init("", readable);
}
*/
bool kinc_g5_texture_unit_equals(kinc_g5_texture_unit_t *unit1, kinc_g5_texture_unit_t *unit2) {
for (int i = 0; i < KINC_G5_SHADER_TYPE_COUNT; ++i) {
if (unit1->stages[i] != unit2->stages[i]) {
return false;
}
}
return true;
}

View File

@ -0,0 +1,98 @@
#pragma once
#include <kinc/global.h>
#include <kinc/image.h>
#include "textureunit.h"
#include <kinc/backend/graphics5/texture.h>
/*! \file texture.h
\brief Provides functions for handling textures.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_texture {
int texWidth;
int texHeight;
kinc_image_format_t format;
Texture5Impl impl;
} kinc_g5_texture_t;
/// <summary>
/// Allocates and initializes a texture without copying any data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="width">The width of the texture to create</param>
/// <param name="height">The height of the texture to create</param>
/// <param name="format">The format of the texture to create</param>
KINC_FUNC void kinc_g5_texture_init(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format);
/// <summary>
/// Allocates and initializes a 3d-texture without copying any data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="width">The width of the texture to create</param>
/// <param name="height">The height of the texture to create</param>
/// <param name="depth">The depth of the texture to create</param>
/// <param name="format">The format of the texture to create</param>
KINC_FUNC void kinc_g5_texture_init3d(kinc_g5_texture_t *texture, int width, int height, int depth, kinc_image_format_t format);
/// <summary>
/// Allocates and initializes a texture and copies image-data into it.
/// </summary>
/// <param name="texture">The texture to initialize</param>
/// <param name="image">The image which's data is copied into the texture</param>
KINC_FUNC void kinc_g5_texture_init_from_image(kinc_g5_texture_t *texture, kinc_image_t *image);
// void kinc_g5_texture_init_from_encoded_data(kinc_g5_texture_t *texture, void *data, int size, const char *format, bool readable);
// void kinc_g5_texture_init_from_data(kinc_g5_texture_t *texture, void *data, int width, int height, int format, bool readable);
KINC_FUNC void kinc_g5_texture_init_non_sampled_access(kinc_g5_texture_t *texture, int width, int height, kinc_image_format_t format);
/// <summary>
/// Deallocates and destroys a texture.
/// </summary>
/// <param name="texture">The texture to destroy</param>
KINC_FUNC void kinc_g5_texture_destroy(kinc_g5_texture_t *texture);
#ifdef KINC_ANDROID
KINC_FUNC void kinc_g5_texture_init_from_id(kinc_g5_texture_t *texture, unsigned texid);
#endif
KINC_FUNC uint8_t *kinc_g5_texture_lock(kinc_g5_texture_t *texture);
KINC_FUNC void kinc_g5_texture_unlock(kinc_g5_texture_t *texture);
/// <summary>
/// Clears parts of a texture to a color.
/// </summary>
KINC_FUNC void kinc_g5_texture_clear(kinc_g5_texture_t *texture, int x, int y, int z, int width, int height, int depth, unsigned color);
#if defined(KINC_IOS) || defined(KINC_MACOS)
KINC_FUNC void kinc_g5_texture_upload(kinc_g5_texture_t *texture, uint8_t *data);
#endif
/// <summary>
/// Generates the mipmap-chain for a texture.
/// </summary>
/// <param name="renderTarget">The render-target to create the mipmaps for</param>
/// <param name="levels">The number of mipmap-levels to generate</param>
KINC_FUNC void kinc_g5_texture_generate_mipmaps(kinc_g5_texture_t *texture, int levels);
KINC_FUNC void kinc_g5_texture_set_mipmap(kinc_g5_texture_t *texture, kinc_image_t *mipmap, int level);
/// <summary>
/// Returns the stride of the first mipmap-layer of the texture in bytes.
/// </summary>
/// <param name="texture">The texture to figure out the stride for</param>
/// <returns>The stride of the first mipmap-layer in bytes</returns>
KINC_FUNC int kinc_g5_texture_stride(kinc_g5_texture_t *texture);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,24 @@
#pragma once
#include <kinc/global.h>
#include <kinc/backend/graphics5/texture.h>
#include <kinc/graphics5/shader.h>
/*! \file textureunit.h
\brief Provides a texture-unit-struct which is used for setting textures in a shader.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_texture_unit {
int stages[KINC_G5_SHADER_TYPE_COUNT];
} kinc_g5_texture_unit_t;
bool kinc_g5_texture_unit_equals(kinc_g5_texture_unit_t *unit1, kinc_g5_texture_unit_t *unit2);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,85 @@
#pragma once
#include <kinc/global.h>
#include "vertexstructure.h"
#include <kinc/backend/graphics5/vertexbuffer.h>
/*! \file vertexbuffer.h
\brief Provides functions for setting up and using vertex-buffers.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_g5_vertex_buffer {
VertexBuffer5Impl impl;
} kinc_g5_vertex_buffer_t;
/// <summary>
/// Allocate and initialize a vertex-buffer.
/// </summary>
/// <param name="buffer">The buffer to initialize</param>
/// <param name="count">The number of vertices in the buffer</param>
/// <param name="structure">The structure of the buffer</param>
/// <param name="gpu_memory">If true, the vertex-buffer will reside in gpu-memory which will make it slower to update but faster to use</param>
/// <param name="instance_data_step_rate">The step-rate for instanced-rendering - use 0 if instanced-rendering will not be used with this buffer</param>
KINC_FUNC void kinc_g5_vertex_buffer_init(kinc_g5_vertex_buffer_t *buffer, int count, kinc_g5_vertex_structure_t *structure, bool gpu_memory,
int instance_data_step_rate);
/// <summary>
/// Destroys a vertex-buffer.
/// </summary>
/// <param name="buffer">The buffer to destroy</param>
KINC_FUNC void kinc_g5_vertex_buffer_destroy(kinc_g5_vertex_buffer_t *buffer);
/// <summary>
/// Locks all of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <returns>The contents of the buffer</returns>
KINC_FUNC float *kinc_g5_vertex_buffer_lock_all(kinc_g5_vertex_buffer_t *buffer);
/// <summary>
/// Locks part of a vertex-buffer to modify its contents.
/// </summary>
/// <param name="buffer">The buffer to lock</param>
/// <param name="start">The index of the first vertex to lock</param>
/// <param name="count">The number of vertices to lock</param>
/// <returns>The contents of the buffer, starting at start</returns>
KINC_FUNC float *kinc_g5_vertex_buffer_lock(kinc_g5_vertex_buffer_t *buffer, int start, int count);
/// <summary>
/// Unlock all of a vertex-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
KINC_FUNC void kinc_g5_vertex_buffer_unlock_all(kinc_g5_vertex_buffer_t *buffer);
/// <summary>
/// Unlocks part of a vertex-buffer so the changed contents can be used.
/// </summary>
/// <param name="buffer">The buffer to unlock</param>
/// <param name="count">The number of vertices to unlock, starting from the start-vertex from the previous lock-call</param>
KINC_FUNC void kinc_g5_vertex_buffer_unlock(kinc_g5_vertex_buffer_t *buffer, int count);
/// <summary>
/// Returns the number of vertices in a buffer.
/// </summary>
/// <param name="buffer">The buffer to figure out the number of vertices for</param>
/// <returns>The number of vertices</returns>
KINC_FUNC int kinc_g5_vertex_buffer_count(kinc_g5_vertex_buffer_t *buffer);
/// <summary>
/// Returns the stride aka the size of one vertex of the buffer in bytes.
/// </summary>
/// <param name="buffer">The buffer to figure out the stride for</param>
/// <returns>The stride of the buffer in bytes</returns>
KINC_FUNC int kinc_g5_vertex_buffer_stride(kinc_g5_vertex_buffer_t *buffer);
int kinc_g5_internal_vertex_buffer_set(kinc_g5_vertex_buffer_t *buffer, int offset);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,45 @@
#pragma once
#include <kinc/global.h>
#include <kinc/graphics4/vertexstructure.h>
/*! \file vertexstructure.h
\brief Provides types for setting up the structure of vertices in a vertex-buffer.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef kinc_g4_vertex_data_t kinc_g5_vertex_data_t;
// typedef kinc_g4_vertex_attribute_t kinc_g5_vertex_attribute_t;
typedef kinc_g4_vertex_element_t kinc_g5_vertex_element_t;
typedef kinc_g4_vertex_structure_t kinc_g5_vertex_structure_t;
/// <summary>
/// Initializes a vertex-structure.
/// </summary>
/// <param name="structure">The structure to initialize</param>
/// <returns></returns>
static inline void kinc_g5_vertex_structure_init(kinc_g5_vertex_structure_t *structure) {
kinc_g4_vertex_structure_init(structure);
}
/// <summary>
/// Adds an element to a vertex-structure.
/// </summary>
/// <param name="structure">The structure to add an element to</param>
/// <param name="name">The name to use for the new element</param>
/// <param name="data">The type of data to assign for the new element</param>
/// <returns></returns>
static inline void kinc_g5_vertex_structure_add(kinc_g5_vertex_structure_t *structure, const char *name, kinc_g5_vertex_data_t data) {
kinc_g4_vertex_structure_add(structure, name, data);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,755 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*! \file image.h
\brief Functionality for creating and loading images. Image loading supports PNG, JPEG and the custom K format. K files can contain image data that uses
texture-compression (see kinc_image_compression).
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_image_compression {
KINC_IMAGE_COMPRESSION_NONE,
KINC_IMAGE_COMPRESSION_DXT5,
KINC_IMAGE_COMPRESSION_ASTC,
KINC_IMAGE_COMPRESSION_PVRTC
} kinc_image_compression_t;
typedef enum kinc_image_format {
KINC_IMAGE_FORMAT_RGBA32,
KINC_IMAGE_FORMAT_GREY8,
KINC_IMAGE_FORMAT_RGB24,
KINC_IMAGE_FORMAT_RGBA128,
KINC_IMAGE_FORMAT_RGBA64,
KINC_IMAGE_FORMAT_A32,
KINC_IMAGE_FORMAT_BGRA32,
KINC_IMAGE_FORMAT_A16
} kinc_image_format_t;
typedef struct kinc_image {
int width, height, depth;
kinc_image_format_t format;
unsigned internal_format;
kinc_image_compression_t compression;
void *data;
size_t data_size;
} kinc_image_t;
typedef struct kinc_image_read_callbacks {
size_t (*read)(void *user_data, void *data, size_t size);
void (*seek)(void *user_data, size_t pos);
size_t (*pos)(void *user_data);
size_t (*size)(void *user_data);
} kinc_image_read_callbacks_t;
/// <summary>
/// Creates a 2D kinc_image in the provided memory.
/// </summary>
/// <returns>The size that's occupied by the image in memory in bytes</returns>
KINC_FUNC size_t kinc_image_init(kinc_image_t *image, void *memory, int width, int height, kinc_image_format_t format);
/// <summary>
/// Creates a 3D kinc_image in the provided memory.
/// </summary>
/// <returns>The size that's occupied by the image in memory in bytes</returns>
KINC_FUNC size_t kinc_image_init3d(kinc_image_t *image, void *memory, int width, int height, int depth, kinc_image_format_t format);
/// <summary>
/// Peeks into an image file and figures out the size it will occupy in memory.
/// </summary>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_size_from_file(const char *filename);
/// <summary>
/// Peeks into an image that is loaded via callback functions and figures out the size it will occupy in memory.
/// </summary>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_size_from_callbacks(kinc_image_read_callbacks_t callbacks, void *user_data, const char *format);
/// <summary>
/// Peeks into an image file that resides in memory and figures out the size it will occupy in memory once it is uncompressed.
/// </summary>
/// <param name="data">The encoded data</param>
/// <param name="data_size">The size of the encoded data</param>
/// <param name="format_hint">Something like "png" can help, it also works to just put in the filename</param>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_size_from_encoded_bytes(void *data, size_t data_size, const char *format_hint);
/// <summary>
/// Loads an image from a file.
/// </summary>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_init_from_file(kinc_image_t *image, void *memory, const char *filename);
/// <summary>
/// Loads an image file using callbacks.
/// </summary>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_init_from_callbacks(kinc_image_t *image, void *memory, kinc_image_read_callbacks_t callbacks, void *user_data, const char *format);
/// <summary>
/// Loads an image file from a memory.
/// </summary>
/// <returns>The memory size in bytes that will be used when loading the image</returns>
KINC_FUNC size_t kinc_image_init_from_encoded_bytes(kinc_image_t *image, void *memory, void *data, size_t data_size, const char *format);
/// <summary>
/// Creates a 2D image from memory.
/// </summary>
KINC_FUNC void kinc_image_init_from_bytes(kinc_image_t *image, void *data, int width, int height, kinc_image_format_t format);
/// <summary>
/// Creates a 3D image from memory.
/// </summary>
KINC_FUNC void kinc_image_init_from_bytes3d(kinc_image_t *image, void *data, int width, int height, int depth, kinc_image_format_t format);
/// <summary>
/// Destroys an image. This does not free the user-provided memory.
/// </summary>
KINC_FUNC void kinc_image_destroy(kinc_image_t *image);
/// <summary>
/// Gets the color value of a 32 bit pixel. If this doesn't fit the format of the image please use kinc_image_at_raw instead.
/// </summary>
/// <returns>One 32 bit color value</returns>
KINC_FUNC uint32_t kinc_image_at(kinc_image_t *image, int x, int y);
/// <summary>
/// Gets a pointer to the color-data of one pixel.
/// </summary>
/// <returns>A pointer to the color-data of the pixel pointed to by x and y</returns>
KINC_FUNC void *kinc_image_at_raw(kinc_image_t *image, int x, int y);
/// <summary>
/// Provides access to the image data.
/// </summary>
/// <returns>A pointer to the image data</returns>
KINC_FUNC uint8_t *kinc_image_get_pixels(kinc_image_t *image);
/// <summary>
/// Gets the size in bytes of a single pixel for a given image format.
/// </summary>
/// <returns>The size of one pixel in bytes</returns>
KINC_FUNC int kinc_image_format_sizeof(kinc_image_format_t format);
#ifdef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include "image.h"
#ifdef KINC_LZ4X
#include <kinc/libs/lz4x.h>
#else
#include <kinc/io/lz4/lz4.h>
#endif
#ifdef KINC_IMPLEMENTATION_ROOT
#undef KINC_IMPLEMENTATION
#endif
#include <kinc/log.h>
#ifdef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#undef KINC_IMPLEMENTATION
#include <kinc/graphics4/graphics.h>
#include <kinc/io/filereader.h>
#include <kinc/math/core.h>
#define KINC_IMPLEMENTATION
#include <string.h>
#define BUFFER_SIZE 4096 * 4096 * 4
static uint8_t buffer[BUFFER_SIZE];
static size_t buffer_offset = 0;
static uint8_t *last_allocated_pointer = 0;
static void *buffer_malloc(size_t size) {
uint8_t *current = &buffer[buffer_offset];
buffer_offset += size + sizeof(size_t);
if (buffer_offset > BUFFER_SIZE) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Not enough memory on image.c Buffer.");
return NULL;
}
memcpy(current, &size, sizeof(*current));
last_allocated_pointer = current + sizeof(size_t);
return current + sizeof(size_t);
}
static void *buffer_realloc(void *p, size_t size) {
if (p == NULL) {
return buffer_malloc(size);
}
uint8_t *old_pointer = (uint8_t *)p;
size_t old_size = *(size_t *)(old_pointer - sizeof(size_t));
if (size <= old_size) {
return old_pointer;
}
else {
if (last_allocated_pointer == old_pointer) {
size_t last_size = &buffer[buffer_offset] - old_pointer;
size_t size_diff = size - last_size;
buffer_offset += size_diff + sizeof(size_t);
return old_pointer;
}
uint8_t *new_pointer = (uint8_t *)buffer_malloc(size);
if (new_pointer == NULL) {
return NULL;
}
memcpy(new_pointer, old_pointer, old_size < size ? old_size : size);
return new_pointer;
}
}
static void buffer_free(void *p) {}
#define STBI_MALLOC(sz) buffer_malloc(sz)
#define STBI_REALLOC(p, newsz) buffer_realloc(p, newsz)
#define STBI_FREE(p) buffer_free(p)
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_STATIC
#ifdef __clang__
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#include <kinc/libs/stb_image.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
typedef struct {
kinc_image_read_callbacks_t callbacks;
void *user_data;
} read_data;
// fill 'data' with 'size' bytes. return number of bytes actually read
static int stb_read(void *user, char *data, int size) {
read_data *reader = (read_data *)user;
return (int)reader->callbacks.read(reader->user_data, data, (size_t)size);
}
// skip the next 'n' bytes, or 'unget' the last -n bytes if negative
static void stb_skip(void *user, int n) {
read_data *reader = (read_data *)user;
reader->callbacks.seek(reader->user_data, reader->callbacks.pos(reader->user_data) + (size_t)n);
}
// returns nonzero if we are at end of file/data
static int stb_eof(void *user) {
read_data *reader = (read_data *)user;
return reader->callbacks.pos(reader->user_data) == reader->callbacks.size(reader->user_data);
}
static _Bool endsWith(const char *str, const char *suffix) {
if (str == NULL || suffix == NULL)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
static size_t loadImageSize(kinc_image_read_callbacks_t callbacks, void *user_data, const char *filename) {
if (endsWith(filename, "k")) {
uint8_t data[4];
callbacks.read(user_data, data, 4);
int width = kinc_read_s32le(data);
callbacks.read(user_data, data, 4);
int height = kinc_read_s32le(data);
char fourcc[5];
callbacks.read(user_data, fourcc, 4);
fourcc[4] = 0;
if (strcmp(fourcc, "LZ4 ") == 0) {
return width * height * 4;
}
else if (strcmp(fourcc, "LZ4F") == 0) {
return width * height * 16;
}
else if (strcmp(fourcc, "ASTC") == 0) {
return width * height * 4; // just an upper bound
}
else if (strcmp(fourcc, "DXT5") == 0) {
return width * height; // just an upper bound
}
else {
kinc_log(KINC_LOG_LEVEL_ERROR, "Unknown fourcc in .k file.");
return 0;
}
}
else if (endsWith(filename, "pvr")) {
uint8_t data[4];
callbacks.read(user_data, data, 4); // version
callbacks.read(user_data, data, 4); // flags
callbacks.read(user_data, data, 4); // pixelFormat1
callbacks.read(user_data, data, 4); // colourSpace
callbacks.read(user_data, data, 4); // channelType
callbacks.read(user_data, data, 4);
uint32_t hh = kinc_read_u32le(data);
callbacks.read(user_data, data, 4);
uint32_t ww = kinc_read_u32le(data);
return ww * hh / 2;
}
else if (endsWith(filename, "hdr")) {
stbi_io_callbacks stbi_callbacks;
stbi_callbacks.eof = stb_eof;
stbi_callbacks.read = stb_read;
stbi_callbacks.skip = stb_skip;
read_data reader;
reader.callbacks = callbacks;
reader.user_data = user_data;
int x, y, comp;
stbi_info_from_callbacks(&stbi_callbacks, &reader, &x, &y, &comp);
buffer_offset = 0;
return x * y * 16;
}
else {
stbi_io_callbacks stbi_callbacks;
stbi_callbacks.eof = stb_eof;
stbi_callbacks.read = stb_read;
stbi_callbacks.skip = stb_skip;
read_data reader;
reader.callbacks = callbacks;
reader.user_data = user_data;
int x, y, comp;
stbi_info_from_callbacks(&stbi_callbacks, &reader, &x, &y, &comp);
buffer_offset = 0;
return x * y * 4;
}
}
static bool loadImage(kinc_image_read_callbacks_t callbacks, void *user_data, const char *filename, uint8_t *output, size_t *outputSize, int *width, int *height,
kinc_image_compression_t *compression, kinc_image_format_t *format, unsigned *internalFormat) {
*format = KINC_IMAGE_FORMAT_RGBA32;
if (endsWith(filename, "k")) {
uint8_t data[4];
callbacks.read(user_data, data, 4);
*width = kinc_read_s32le(data);
callbacks.read(user_data, data, 4);
*height = kinc_read_s32le(data);
char fourcc[5];
callbacks.read(user_data, fourcc, 4);
fourcc[4] = 0;
int compressedSize = (int)callbacks.size(user_data) - 12;
if (strcmp(fourcc, "LZ4 ") == 0) {
*compression = KINC_IMAGE_COMPRESSION_NONE;
*internalFormat = 0;
*outputSize = (size_t)(*width * *height * 4);
callbacks.read(user_data, buffer, compressedSize);
LZ4_decompress_safe((char *)buffer, (char *)output, compressedSize, (int)*outputSize);
return true;
}
else if (strcmp(fourcc, "LZ4F") == 0) {
*compression = KINC_IMAGE_COMPRESSION_NONE;
*internalFormat = 0;
*outputSize = (size_t)(*width * *height * 16);
callbacks.read(user_data, buffer, compressedSize);
LZ4_decompress_safe((char *)buffer, (char *)output, compressedSize, (int)*outputSize);
*format = KINC_IMAGE_FORMAT_RGBA128;
return true;
}
else if (strcmp(fourcc, "ASTC") == 0) {
*compression = KINC_IMAGE_COMPRESSION_ASTC;
*outputSize = (size_t)(*width * *height * 4);
callbacks.read(user_data, buffer, compressedSize);
*outputSize = LZ4_decompress_safe((char *)buffer, (char *)output, compressedSize, (int)*outputSize);
uint8_t blockdim_x = 6;
uint8_t blockdim_y = 6;
*internalFormat = (blockdim_x << 8) + blockdim_y;
return true;
/*int index = 0;
index += 4; // magic
u8 blockdim_x = astcdata[index++];
u8 blockdim_y = astcdata[index++];
++index; // blockdim_z
internalFormat = (blockdim_x << 8) + blockdim_y;
u8 xsize[4];
xsize[0] = astcdata[index++];
xsize[1] = astcdata[index++];
xsize[2] = astcdata[index++];
xsize[3] = 0;
this->width = *(unsigned*)&xsize[0];
u8 ysize[4];
ysize[0] = astcdata[index++];
ysize[1] = astcdata[index++];
ysize[2] = astcdata[index++];
ysize[3] = 0;
this->height = *(unsigned*)&ysize[0];
u8 zsize[3];
zsize[0] = astcdata[index++];
zsize[1] = astcdata[index++];
zsize[2] = astcdata[index++];
u8* all = (u8*)astcdata[index];
dataSize -= 16;
this->data = new u8[dataSize];
for (int i = 0; i < dataSize; ++i) {
data[i] = all[16 + i];
}
free(astcdata);*/
}
else if (strcmp(fourcc, "DXT5") == 0) {
*compression = KINC_IMAGE_COMPRESSION_DXT5;
*outputSize = (size_t)(*width * *height);
callbacks.read(user_data, buffer, compressedSize);
*outputSize = LZ4_decompress_safe((char *)buffer, (char *)output, compressedSize, (int)*outputSize);
*internalFormat = 0;
return true;
}
else {
kinc_log(KINC_LOG_LEVEL_ERROR, "Unknown fourcc in .k file.");
return false;
}
}
else if (endsWith(filename, "pvr")) {
uint8_t data[4];
callbacks.read(user_data, data, 4); // version
callbacks.read(user_data, data, 4); // flags
callbacks.read(user_data, data, 4); // pixelFormat1
callbacks.read(user_data, data, 4); // colourSpace
callbacks.read(user_data, data, 4); // channelType
callbacks.read(user_data, data, 4);
uint32_t hh = kinc_read_u32le(data);
callbacks.read(user_data, data, 4);
uint32_t ww = kinc_read_u32le(data);
callbacks.read(user_data, data, 4); // depth
callbacks.read(user_data, data, 4); // numSurfaces
callbacks.read(user_data, data, 4); // numFaces
callbacks.read(user_data, data, 4); // mipMapCount
callbacks.read(user_data, data, 4);
callbacks.read(user_data, data, 4);
uint32_t meta1fourcc = kinc_read_u32le(data);
callbacks.read(user_data, data, 4); // meta1key
callbacks.read(user_data, data, 4); // meta1size
callbacks.read(user_data, data, 4);
uint32_t meta1data = kinc_read_u32le(data);
callbacks.read(user_data, data, 4);
uint32_t meta2fourcc = kinc_read_u32le(data);
callbacks.read(user_data, data, 4); // meta2key
callbacks.read(user_data, data, 4); // meta2size
callbacks.read(user_data, data, 4);
uint32_t meta2data = kinc_read_u32le(data);
int w = 0;
int h = 0;
if (meta1fourcc == 0)
w = meta1data;
if (meta1fourcc == 1)
h = meta1data;
if (meta2fourcc == 0)
w = meta2data;
if (meta2fourcc == 1)
h = meta2data;
*width = w;
*height = h;
*compression = KINC_IMAGE_COMPRESSION_PVRTC;
*internalFormat = 0;
*outputSize = (size_t)(ww * hh / 2);
callbacks.read(user_data, output, *outputSize);
return true;
}
else if (endsWith(filename, "hdr")) {
*compression = KINC_IMAGE_COMPRESSION_NONE;
*internalFormat = 0;
stbi_io_callbacks stbi_callbacks;
stbi_callbacks.eof = stb_eof;
stbi_callbacks.read = stb_read;
stbi_callbacks.skip = stb_skip;
read_data reader;
reader.callbacks = callbacks;
reader.user_data = user_data;
int comp;
float *uncompressed = stbi_loadf_from_callbacks(&stbi_callbacks, &reader, width, height, &comp, 4);
if (uncompressed == NULL) {
kinc_log(KINC_LOG_LEVEL_ERROR, stbi_failure_reason());
return false;
}
*outputSize = (size_t)(*width * *height * 16);
memcpy(output, uncompressed, *outputSize);
*format = KINC_IMAGE_FORMAT_RGBA128;
buffer_offset = 0;
return true;
}
else {
*compression = KINC_IMAGE_COMPRESSION_NONE;
*internalFormat = 0;
stbi_io_callbacks stbi_callbacks;
stbi_callbacks.eof = stb_eof;
stbi_callbacks.read = stb_read;
stbi_callbacks.skip = stb_skip;
read_data reader;
reader.callbacks = callbacks;
reader.user_data = user_data;
int comp;
uint8_t *uncompressed = stbi_load_from_callbacks(&stbi_callbacks, &reader, width, height, &comp, 4);
if (uncompressed == NULL) {
kinc_log(KINC_LOG_LEVEL_ERROR, stbi_failure_reason());
return false;
}
for (int y = 0; y < *height; ++y) {
for (int x = 0; x < *width; ++x) {
float r = uncompressed[y * *width * 4 + x * 4 + 0] / 255.0f;
float g = uncompressed[y * *width * 4 + x * 4 + 1] / 255.0f;
float b = uncompressed[y * *width * 4 + x * 4 + 2] / 255.0f;
float a = uncompressed[y * *width * 4 + x * 4 + 3] / 255.0f;
r *= a;
g *= a;
b *= a;
output[y * *width * 4 + x * 4 + 0] = (uint8_t)kinc_round(r * 255.0f);
output[y * *width * 4 + x * 4 + 1] = (uint8_t)kinc_round(g * 255.0f);
output[y * *width * 4 + x * 4 + 2] = (uint8_t)kinc_round(b * 255.0f);
output[y * *width * 4 + x * 4 + 3] = (uint8_t)kinc_round(a * 255.0f);
}
}
*outputSize = (size_t)(*width * *height * 4);
buffer_offset = 0;
return true;
}
}
int kinc_image_format_sizeof(kinc_image_format_t format) {
switch (format) {
case KINC_IMAGE_FORMAT_RGBA128:
return 16;
case KINC_IMAGE_FORMAT_RGBA32:
case KINC_IMAGE_FORMAT_BGRA32:
return 4;
case KINC_IMAGE_FORMAT_RGBA64:
return 8;
case KINC_IMAGE_FORMAT_A32:
return 4;
case KINC_IMAGE_FORMAT_A16:
return 2;
case KINC_IMAGE_FORMAT_GREY8:
return 1;
case KINC_IMAGE_FORMAT_RGB24:
return 3;
}
return -1;
}
// static bool formatIsFloatingPoint(kinc_image_format_t format) {
// return format == KINC_IMAGE_FORMAT_RGBA128 || format == KINC_IMAGE_FORMAT_RGBA64 || format == KINC_IMAGE_FORMAT_A32 || format == KINC_IMAGE_FORMAT_A16;
//}
size_t kinc_image_init(kinc_image_t *image, void *memory, int width, int height, kinc_image_format_t format) {
return kinc_image_init3d(image, memory, width, height, 1, format);
}
size_t kinc_image_init3d(kinc_image_t *image, void *memory, int width, int height, int depth, kinc_image_format_t format) {
image->width = width;
image->height = height;
image->depth = depth;
image->format = format;
image->compression = KINC_IMAGE_COMPRESSION_NONE;
image->data = memory;
return width * height * depth * kinc_image_format_sizeof(format);
}
void kinc_image_init_from_bytes(kinc_image_t *image, void *data, int width, int height, kinc_image_format_t format) {
kinc_image_init_from_bytes3d(image, data, width, height, 1, format);
}
void kinc_image_init_from_bytes3d(kinc_image_t *image, void *data, int width, int height, int depth, kinc_image_format_t format) {
image->width = width;
image->height = height;
image->depth = depth;
image->format = format;
image->compression = KINC_IMAGE_COMPRESSION_NONE;
image->data = data;
}
static size_t read_callback(void *user_data, void *data, size_t size) {
return kinc_file_reader_read((kinc_file_reader_t *)user_data, data, size);
}
static size_t size_callback(void *user_data) {
return kinc_file_reader_size((kinc_file_reader_t *)user_data);
}
static size_t pos_callback(void *user_data) {
return kinc_file_reader_pos((kinc_file_reader_t *)user_data);
}
static void seek_callback(void *user_data, size_t pos) {
kinc_file_reader_seek((kinc_file_reader_t *)user_data, pos);
}
struct kinc_internal_image_memory {
uint8_t *data;
size_t size;
size_t offset;
};
static size_t memory_read_callback(void *user_data, void *data, size_t size) {
struct kinc_internal_image_memory *memory = (struct kinc_internal_image_memory *)user_data;
size_t read_size = memory->size - memory->offset < size ? memory->size - memory->offset : size;
memcpy(data, &memory->data[memory->offset], read_size);
memory->offset += read_size;
return read_size;
}
static size_t memory_size_callback(void *user_data) {
struct kinc_internal_image_memory *memory = (struct kinc_internal_image_memory *)user_data;
return memory->size;
}
static size_t memory_pos_callback(void *user_data) {
struct kinc_internal_image_memory *memory = (struct kinc_internal_image_memory *)user_data;
return memory->offset;
}
static void memory_seek_callback(void *user_data, size_t pos) {
struct kinc_internal_image_memory *memory = (struct kinc_internal_image_memory *)user_data;
memory->offset = pos;
}
size_t kinc_image_size_from_callbacks(kinc_image_read_callbacks_t callbacks, void *user_data, const char *filename) {
return loadImageSize(callbacks, user_data, filename);
}
size_t kinc_image_size_from_file(const char *filename) {
kinc_file_reader_t reader;
if (kinc_file_reader_open(&reader, filename, KINC_FILE_TYPE_ASSET)) {
kinc_image_read_callbacks_t callbacks;
callbacks.read = read_callback;
callbacks.size = size_callback;
callbacks.pos = pos_callback;
callbacks.seek = seek_callback;
size_t dataSize = loadImageSize(callbacks, &reader, filename);
kinc_file_reader_close(&reader);
return dataSize;
}
return 0;
}
size_t kinc_image_size_from_encoded_bytes(void *data, size_t data_size, const char *format) {
kinc_image_read_callbacks_t callbacks;
callbacks.read = memory_read_callback;
callbacks.size = memory_size_callback;
callbacks.pos = memory_pos_callback;
callbacks.seek = memory_seek_callback;
struct kinc_internal_image_memory image_memory;
image_memory.data = (uint8_t *)data;
image_memory.size = data_size;
image_memory.offset = 0;
return loadImageSize(callbacks, &image_memory, format);
}
size_t kinc_image_init_from_callbacks(kinc_image_t *image, void *memory, kinc_image_read_callbacks_t callbacks, void *user_data, const char *filename) {
size_t dataSize = 0;
loadImage(callbacks, user_data, filename, memory, &dataSize, &image->width, &image->height, &image->compression, &image->format, &image->internal_format);
image->data = memory;
image->data_size = dataSize;
return dataSize;
}
size_t kinc_image_init_from_file(kinc_image_t *image, void *memory, const char *filename) {
kinc_file_reader_t reader;
if (kinc_file_reader_open(&reader, filename, KINC_FILE_TYPE_ASSET)) {
kinc_image_read_callbacks_t callbacks;
callbacks.read = read_callback;
callbacks.size = size_callback;
callbacks.pos = pos_callback;
callbacks.seek = seek_callback;
size_t dataSize = 0;
loadImage(callbacks, &reader, filename, memory, &dataSize, &image->width, &image->height, &image->compression, &image->format, &image->internal_format);
kinc_file_reader_close(&reader);
image->data = memory;
image->data_size = dataSize;
image->depth = 1;
return dataSize;
}
return 0;
}
size_t kinc_image_init_from_encoded_bytes(kinc_image_t *image, void *memory, void *data, size_t data_size, const char *format) {
kinc_image_read_callbacks_t callbacks;
callbacks.read = memory_read_callback;
callbacks.size = memory_size_callback;
callbacks.pos = memory_pos_callback;
callbacks.seek = memory_seek_callback;
struct kinc_internal_image_memory image_memory;
image_memory.data = (uint8_t *)data;
image_memory.size = data_size;
image_memory.offset = 0;
size_t dataSize = 0;
loadImage(callbacks, &image_memory, format, memory, &dataSize, &image->width, &image->height, &image->compression, &image->format, &image->internal_format);
image->data = memory;
image->data_size = dataSize;
image->depth = 1;
return dataSize;
}
void kinc_image_destroy(kinc_image_t *image) {
// user has to free the data
image->data = NULL;
}
uint32_t kinc_image_at(kinc_image_t *image, int x, int y) {
if (image->data == NULL) {
return 0;
}
else {
return *(uint32_t *)&((uint8_t *)image->data)[image->width * kinc_image_format_sizeof(image->format) * y + x * kinc_image_format_sizeof(image->format)];
}
}
void *kinc_image_at_raw(kinc_image_t *image, int x, int y) {
if (image->data == NULL) {
return NULL;
}
else {
return &((uint8_t *)image->data)[image->width * kinc_image_format_sizeof(image->format) * y + x * kinc_image_format_sizeof(image->format)];
}
}
uint8_t *kinc_image_get_pixels(kinc_image_t *image) {
return (uint8_t *)image->data;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,46 @@
#pragma once
#include <kinc/global.h>
/*! \file acceleration.h
\brief Provides data provided by acceleration-sensors.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Sets the acceleration-callback which is called with measured acceleration-data in three dimensions.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_acceleration_set_callback(void (*value)(float /*x*/, float /*y*/, float /*z*/));
void kinc_internal_on_acceleration(float x, float y, float z);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
void (*acceleration_callback)(float /*x*/, float /*y*/, float /*z*/) = NULL;
void kinc_acceleration_set_callback(void (*value)(float /*x*/, float /*y*/, float /*z*/)) {
acceleration_callback = value;
}
void kinc_internal_on_acceleration(float x, float y, float z) {
if (acceleration_callback != NULL) {
acceleration_callback(x, y, z);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,143 @@
#pragma once
#include <kinc/global.h>
/*! \file gamepad.h
\brief Provides gamepad-support.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_GAMEPAD_MAX_COUNT 12
/// <summary>
/// Sets the gamepad-connect-callback which is called when a gamepad is connected.
/// </summary>
/// <param name="value">The callback</param>
/// <param name="userdata">Userdata you will receive back as the 2nd callback parameter</param>
KINC_FUNC void kinc_gamepad_set_connect_callback(void (*value)(int /*gamepad*/, void * /*userdata*/), void *userdata);
/// <summary>
/// Sets the gamepad-disconnect-callback which is called when a gamepad is disconnected.
/// </summary>
/// <param name="value">The callback</param>
/// <param name="userdata">Userdata you will receive back as the 2nd callback parameter</param>
KINC_FUNC void kinc_gamepad_set_disconnect_callback(void (*value)(int /*gamepad*/, void * /*userdata*/), void *userdata);
/// <summary>
/// Sets the gamepad-axis-callback which is called with data about changing gamepad-sticks.
/// </summary>
/// <param name="value">The callback</param>
/// <param name="userdata">Userdata you will receive back as the 4th callback parameter</param>
KINC_FUNC void kinc_gamepad_set_axis_callback(void (*value)(int /*gamepad*/, int /*axis*/, float /*value*/, void * /*userdata*/), void *userdata);
/// <summary>
/// Sets the gamepad-button-callback which is called with data about changing gamepad-buttons.
/// </summary>
/// <param name="value">The callback</param>
/// <param name="userdata">Userdata you will receive back as the 4th callback parameter</param>
KINC_FUNC void kinc_gamepad_set_button_callback(void (*value)(int /*gamepad*/, int /*button*/, float /*value*/, void * /*userdata*/), void *userdata);
/// <summary>
/// Returns a vendor-name for a gamepad.
/// </summary>
/// <param name="gamepad">The index of the gamepad for which to receive the vendor-name</param>
/// <returns>The vendor-name</returns>
KINC_FUNC const char *kinc_gamepad_vendor(int gamepad);
/// <summary>
/// Returns a name for a gamepad.
/// </summary>
/// <param name="gamepad">The index of the gamepad for which to receive the name</param>
/// <returns>The gamepad's name</returns>
KINC_FUNC const char *kinc_gamepad_product_name(int gamepad);
/// <summary>
/// Checks whether a gamepad is connected.
/// </summary>
/// <param name="gamepad">The index of the gamepad which's connection will be checked</param>
/// <returns>Whether a gamepad is connected for the gamepad-index</returns>
KINC_FUNC bool kinc_gamepad_connected(int gamepad);
/// <summary>
/// Rumbles a gamepad. Careful here because it might just fall off your table.
/// </summary>
/// <param name="gamepad">The index of the gamepad to rumble</param>
/// <param name="left">Rumble-strength for the left motor between 0 and 1</param>
/// <param name="right">Rumble-strength for the right motor between 0 and 1</param>
KINC_FUNC void kinc_gamepad_rumble(int gamepad, float left, float right);
void kinc_internal_gamepad_trigger_connect(int gamepad);
void kinc_internal_gamepad_trigger_disconnect(int gamepad);
void kinc_internal_gamepad_trigger_axis(int gamepad, int axis, float value);
void kinc_internal_gamepad_trigger_button(int gamepad, int button, float value);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*gamepad_connect_callback)(int /*gamepad*/, void * /*userdata*/) = NULL;
static void *gamepad_connect_callback_userdata = NULL;
static void (*gamepad_disconnect_callback)(int /*gamepad*/, void * /*userdata*/) = NULL;
static void *gamepad_disconnect_callback_userdata = NULL;
static void (*gamepad_axis_callback)(int /*gamepad*/, int /*axis*/, float /*value*/, void * /*userdata*/) = NULL;
static void *gamepad_axis_callback_userdata = NULL;
static void (*gamepad_button_callback)(int /*gamepad*/, int /*button*/, float /*value*/, void * /*userdata*/) = NULL;
static void *gamepad_button_callback_userdata = NULL;
void kinc_gamepad_set_connect_callback(void (*value)(int /*gamepad*/, void * /*userdata*/), void *userdata) {
gamepad_connect_callback = value;
gamepad_connect_callback_userdata = userdata;
}
void kinc_gamepad_set_disconnect_callback(void (*value)(int /*gamepad*/, void * /*userdata*/), void *userdata) {
gamepad_disconnect_callback = value;
gamepad_disconnect_callback_userdata = userdata;
}
void kinc_gamepad_set_axis_callback(void (*value)(int /*gamepad*/, int /*axis*/, float /*value*/, void * /*userdata*/), void *userdata) {
gamepad_axis_callback = value;
gamepad_axis_callback_userdata = userdata;
}
void kinc_gamepad_set_button_callback(void (*value)(int /*gamepad*/, int /*button*/, float /*value*/, void * /*userdata*/), void *userdata) {
gamepad_button_callback = value;
gamepad_button_callback_userdata = userdata;
}
void kinc_internal_gamepad_trigger_connect(int gamepad) {
if (gamepad_connect_callback != NULL) {
gamepad_connect_callback(gamepad, gamepad_connect_callback_userdata);
}
}
void kinc_internal_gamepad_trigger_disconnect(int gamepad) {
if (gamepad_disconnect_callback != NULL) {
gamepad_disconnect_callback(gamepad, gamepad_disconnect_callback_userdata);
}
}
void kinc_internal_gamepad_trigger_axis(int gamepad, int axis, float value) {
if (gamepad_axis_callback != NULL) {
gamepad_axis_callback(gamepad, axis, value, gamepad_axis_callback_userdata);
}
}
void kinc_internal_gamepad_trigger_button(int gamepad, int button, float value) {
if (gamepad_button_callback != NULL) {
gamepad_button_callback(gamepad, button, value, gamepad_button_callback_userdata);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,9 @@
#define KINC_IMPLEMENTATION_INPUT
#include "acceleration.h"
#include "gamepad.h"
#include "keyboard.h"
#include "mouse.h"
#include "pen.h"
#include "rotation.h"
#include "surface.h"

View File

@ -0,0 +1,294 @@
#pragma once
#include <kinc/global.h>
/*! \file keyboard.h
\brief Provides keyboard-support.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_KEY_UNKNOWN 0
#define KINC_KEY_BACK 1 // Android
#define KINC_KEY_CANCEL 3
#define KINC_KEY_HELP 6
#define KINC_KEY_BACKSPACE 8
#define KINC_KEY_TAB 9
#define KINC_KEY_CLEAR 12
#define KINC_KEY_RETURN 13
#define KINC_KEY_SHIFT 16
#define KINC_KEY_CONTROL 17
#define KINC_KEY_ALT 18
#define KINC_KEY_PAUSE 19
#define KINC_KEY_CAPS_LOCK 20
#define KINC_KEY_KANA 21
#define KINC_KEY_HANGUL 21
#define KINC_KEY_EISU 22
#define KINC_KEY_JUNJA 23
#define KINC_KEY_FINAL 24
#define KINC_KEY_HANJA 25
#define KINC_KEY_KANJI 25
#define KINC_KEY_ESCAPE 27
#define KINC_KEY_CONVERT 28
#define KINC_KEY_NON_CONVERT 29
#define KINC_KEY_ACCEPT 30
#define KINC_KEY_MODE_CHANGE 31
#define KINC_KEY_SPACE 32
#define KINC_KEY_PAGE_UP 33
#define KINC_KEY_PAGE_DOWN 34
#define KINC_KEY_END 35
#define KINC_KEY_HOME 36
#define KINC_KEY_LEFT 37
#define KINC_KEY_UP 38
#define KINC_KEY_RIGHT 39
#define KINC_KEY_DOWN 40
#define KINC_KEY_SELECT 41
#define KINC_KEY_PRINT 42
#define KINC_KEY_EXECUTE 43
#define KINC_KEY_PRINT_SCREEN 44
#define KINC_KEY_INSERT 45
#define KINC_KEY_DELETE 46
#define KINC_KEY_0 48
#define KINC_KEY_1 49
#define KINC_KEY_2 50
#define KINC_KEY_3 51
#define KINC_KEY_4 52
#define KINC_KEY_5 53
#define KINC_KEY_6 54
#define KINC_KEY_7 55
#define KINC_KEY_8 56
#define KINC_KEY_9 57
#define KINC_KEY_COLON 58
#define KINC_KEY_SEMICOLON 59
#define KINC_KEY_LESS_THAN 60
#define KINC_KEY_EQUALS 61
#define KINC_KEY_GREATER_THAN 62
#define KINC_KEY_QUESTIONMARK 63
#define KINC_KEY_AT 64
#define KINC_KEY_A 65
#define KINC_KEY_B 66
#define KINC_KEY_C 67
#define KINC_KEY_D 68
#define KINC_KEY_E 69
#define KINC_KEY_F 70
#define KINC_KEY_G 71
#define KINC_KEY_H 72
#define KINC_KEY_I 73
#define KINC_KEY_J 74
#define KINC_KEY_K 75
#define KINC_KEY_L 76
#define KINC_KEY_M 77
#define KINC_KEY_N 78
#define KINC_KEY_O 79
#define KINC_KEY_P 80
#define KINC_KEY_Q 81
#define KINC_KEY_R 82
#define KINC_KEY_S 83
#define KINC_KEY_T 84
#define KINC_KEY_U 85
#define KINC_KEY_V 86
#define KINC_KEY_W 87
#define KINC_KEY_X 88
#define KINC_KEY_Y 89
#define KINC_KEY_Z 90
#define KINC_KEY_WIN 91
#define KINC_KEY_CONTEXT_MENU 93
#define KINC_KEY_SLEEP 95
#define KINC_KEY_NUMPAD_0 96
#define KINC_KEY_NUMPAD_1 97
#define KINC_KEY_NUMPAD_2 98
#define KINC_KEY_NUMPAD_3 99
#define KINC_KEY_NUMPAD_4 100
#define KINC_KEY_NUMPAD_5 101
#define KINC_KEY_NUMPAD_6 102
#define KINC_KEY_NUMPAD_7 103
#define KINC_KEY_NUMPAD_8 104
#define KINC_KEY_NUMPAD_9 105
#define KINC_KEY_MULTIPLY 106
#define KINC_KEY_ADD 107
#define KINC_KEY_SEPARATOR 108
#define KINC_KEY_SUBTRACT 109
#define KINC_KEY_DECIMAL 110
#define KINC_KEY_DIVIDE 111
#define KINC_KEY_F1 112
#define KINC_KEY_F2 113
#define KINC_KEY_F3 114
#define KINC_KEY_F4 115
#define KINC_KEY_F5 116
#define KINC_KEY_F6 117
#define KINC_KEY_F7 118
#define KINC_KEY_F8 119
#define KINC_KEY_F9 120
#define KINC_KEY_F10 121
#define KINC_KEY_F11 122
#define KINC_KEY_F12 123
#define KINC_KEY_F13 124
#define KINC_KEY_F14 125
#define KINC_KEY_F15 126
#define KINC_KEY_F16 127
#define KINC_KEY_F17 128
#define KINC_KEY_F18 129
#define KINC_KEY_F19 130
#define KINC_KEY_F20 131
#define KINC_KEY_F21 132
#define KINC_KEY_F22 133
#define KINC_KEY_F23 134
#define KINC_KEY_F24 135
#define KINC_KEY_NUM_LOCK 144
#define KINC_KEY_SCROLL_LOCK 145
#define KINC_KEY_WIN_OEM_FJ_JISHO 146
#define KINC_KEY_WIN_OEM_FJ_MASSHOU 147
#define KINC_KEY_WIN_OEM_FJ_TOUROKU 148
#define KINC_KEY_WIN_OEM_FJ_LOYA 149
#define KINC_KEY_WIN_OEM_FJ_ROYA 150
#define KINC_KEY_CIRCUMFLEX 160
#define KINC_KEY_EXCLAMATION 161
#define KINC_KEY_DOUBLE_QUOTE 162
#define KINC_KEY_HASH 163
#define KINC_KEY_DOLLAR 164
#define KINC_KEY_PERCENT 165
#define KINC_KEY_AMPERSAND 166
#define KINC_KEY_UNDERSCORE 167
#define KINC_KEY_OPEN_PAREN 168
#define KINC_KEY_CLOSE_PAREN 169
#define KINC_KEY_ASTERISK 170
#define KINC_KEY_PLUS 171
#define KINC_KEY_PIPE 172
#define KINC_KEY_HYPHEN_MINUS 173
#define KINC_KEY_OPEN_CURLY_BRACKET 174
#define KINC_KEY_CLOSE_CURLY_BRACKET 175
#define KINC_KEY_TILDE 176
#define KINC_KEY_VOLUME_MUTE 181
#define KINC_KEY_VOLUME_DOWN 182
#define KINC_KEY_VOLUME_UP 183
#define KINC_KEY_COMMA 188
#define KINC_KEY_PERIOD 190
#define KINC_KEY_SLASH 191
#define KINC_KEY_BACK_QUOTE 192
#define KINC_KEY_OPEN_BRACKET 219
#define KINC_KEY_BACK_SLASH 220
#define KINC_KEY_CLOSE_BRACKET 221
#define KINC_KEY_QUOTE 222
#define KINC_KEY_META 224
#define KINC_KEY_ALT_GR 225
#define KINC_KEY_WIN_ICO_HELP 227
#define KINC_KEY_WIN_ICO_00 228
#define KINC_KEY_WIN_ICO_CLEAR 230
#define KINC_KEY_WIN_OEM_RESET 233
#define KINC_KEY_WIN_OEM_JUMP 234
#define KINC_KEY_WIN_OEM_PA1 235
#define KINC_KEY_WIN_OEM_PA2 236
#define KINC_KEY_WIN_OEM_PA3 237
#define KINC_KEY_WIN_OEM_WSCTRL 238
#define KINC_KEY_WIN_OEM_CUSEL 239
#define KINC_KEY_WIN_OEM_ATTN 240
#define KINC_KEY_WIN_OEM_FINISH 241
#define KINC_KEY_WIN_OEM_COPY 242
#define KINC_KEY_WIN_OEM_AUTO 243
#define KINC_KEY_WIN_OEM_ENLW 244
#define KINC_KEY_WIN_OEM_BACK_TAB 245
#define KINC_KEY_ATTN 246
#define KINC_KEY_CRSEL 247
#define KINC_KEY_EXSEL 248
#define KINC_KEY_EREOF 249
#define KINC_KEY_PLAY 250
#define KINC_KEY_ZOOM 251
#define KINC_KEY_PA1 253
#define KINC_KEY_WIN_OEM_CLEAR 254
/// <summary>
/// Show the keyboard if the system is using a software-keyboard.
/// </summary>
KINC_FUNC void kinc_keyboard_show(void);
/// <summary>
/// Hide the keyboard if the system is using a software-keyboard.
/// </summary>
KINC_FUNC void kinc_keyboard_hide(void);
/// <summary>
/// Figure out whether the keyboard is currently shown if the system is using a software-keyboard.
/// </summary>
/// <returns>Whether the keyboard is currently shown</returns>
KINC_FUNC bool kinc_keyboard_active(void);
/// <summary>
/// Sets the keyboard-key-down-callback which is called with a key-code when a key goes down. Do not use this for text-input, that's what the key-press-callback
/// is here for.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_keyboard_set_key_down_callback(void (*value)(int /*key_code*/, void * /*data*/), void *data);
/// <summary>
/// Sets the keyboard-key-up-callback which is called with a key-code when a key goes up. Do not use this for text-input, that's what the key-press-callback is
/// here for.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_keyboard_set_key_up_callback(void (*value)(int /*key_code*/, void * /*data*/), void *data);
/// <summary>
/// Sets the keyboard-key-press-callback which is called when the system decides that a character came in via the keyboard. Use this for text-input.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_keyboard_set_key_press_callback(void (*value)(unsigned /*character*/, void * /*data*/), void *data);
void kinc_internal_keyboard_trigger_key_down(int key_code);
void kinc_internal_keyboard_trigger_key_up(int key_code);
void kinc_internal_keyboard_trigger_key_press(unsigned character);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*keyboard_key_down_callback)(int /*key_code*/, void * /*data*/) = NULL;
static void *keyboard_key_down_callback_data = NULL;
static void (*keyboard_key_up_callback)(int /*key_code*/, void * /*data*/) = NULL;
static void *keyboard_key_up_callback_data = NULL;
static void (*keyboard_key_press_callback)(unsigned /*character*/, void * /*data*/) = NULL;
static void *keyboard_key_press_callback_data = NULL;
void kinc_keyboard_set_key_down_callback(void (*value)(int /*key_code*/, void * /*data*/), void *data) {
keyboard_key_down_callback = value;
keyboard_key_down_callback_data = data;
}
void kinc_keyboard_set_key_up_callback(void (*value)(int /*key_code*/, void * /*data*/), void *data) {
keyboard_key_up_callback = value;
keyboard_key_up_callback_data = data;
}
void kinc_keyboard_set_key_press_callback(void (*value)(unsigned /*character*/, void * /*data*/), void *data) {
keyboard_key_press_callback = value;
keyboard_key_press_callback_data = data;
}
void kinc_internal_keyboard_trigger_key_down(int key_code) {
if (keyboard_key_down_callback != NULL) {
keyboard_key_down_callback(key_code, keyboard_key_down_callback_data);
}
}
void kinc_internal_keyboard_trigger_key_up(int key_code) {
if (keyboard_key_up_callback != NULL) {
keyboard_key_up_callback(key_code, keyboard_key_up_callback_data);
}
}
void kinc_internal_keyboard_trigger_key_press(unsigned character) {
if (keyboard_key_press_callback != NULL) {
keyboard_key_press_callback(character, keyboard_key_press_callback_data);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,297 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
/*! \file mouse.h
\brief Provides mouse-support.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_MOUSE_LEFT 0
#define KINC_MOUSE_RIGHT 1
#define KINC_MOUSE_MIDDLE 2
// eg backward sidebutton
#define KINC_MOUSE_EXTRA1 3
// eg forward sidebutton
#define KINC_MOUSE_EXTRA2 4
/// <summary>
/// Sets the mouse-press-callback which is called when a mouse-button is pressed.
/// The button callback argument will usually contain one of the KINC_MOUSE_* values,
/// but can contain higher values on certain platforms when mice with a lot of buttons are used.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_press_callback(void (*value)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/), void *data);
/// <summary>
/// Sets the mouse-release-callback which is called when a mouse-button is released.
/// The button callback argument will usually contain one of the KINC_MOUSE_* values,
/// but can contain higher values on certain platforms when mice with a lot of buttons are used.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_release_callback(void (*value)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/), void *data);
/// <summary>
/// Sets the mouse-move-callback which is called when the mouse is moved.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, int /*movement_x*/, int /*movement_y*/, void * /*data*/),
void *data);
/// <summary>
/// Sets the mouse-scroll-callback which is called when the mouse wheel is spinning.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_scroll_callback(void (*value)(int /*window*/, int /*delta*/, void * /*data*/), void *data);
/// <summary>
/// Sets the mouse-enter-window-callback which is called when the mouse-cursor enters the application-window.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_enter_window_callback(void (*value)(int /*window*/, void * /*data*/), void *data);
/// <summary>
/// Sets the mouse-leave-window-callback which is called when the mouse-cursor leaves the application-window.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_mouse_set_leave_window_callback(void (*value)(int /*window*/, void * /*data*/), void *data);
/// <summary>
/// Figures out whether mouse-locking is supported.
/// </summary>
/// <returns>Whether mouse-locking is supported</returns>
KINC_FUNC bool kinc_mouse_can_lock(void);
/// <summary>
/// Figures out whether the mouse is currently locked.
/// </summary>
/// <returns>Whether the mouse is currently locked</returns>
KINC_FUNC bool kinc_mouse_is_locked(void);
/// <summary>
/// Locks the mouse to a window.
/// </summary>
/// <param name="window">The window to lock the mouse to</param>
KINC_FUNC void kinc_mouse_lock(int window);
/// <summary>
/// Unlocks the mouse.
/// </summary>
/// <param name=""></param>
/// <returns></returns>
KINC_FUNC void kinc_mouse_unlock(void);
/// <summary>
/// Change the cursor-image to something that's semi-randomly based on the provided int.
/// </summary>
/// <param name="cursor">Defines what the cursor is changed to - somehow</param>
KINC_FUNC void kinc_mouse_set_cursor(int cursor);
/// <summary>
/// Shows the mouse-cursor.
/// </summary>
KINC_FUNC void kinc_mouse_show(void);
/// <summary>
/// Hides the mouse-cursor.
/// </summary>
KINC_FUNC void kinc_mouse_hide(void);
/// <summary>
/// Manually sets the mouse-cursor-position.
/// </summary>
/// <param name="window">The window to place the cursor in</param>
/// <param name="x">The x-position inside the window to place the cursor at</param>
/// <param name="y">The y-position inside the window to place the cursor at</param>
KINC_FUNC void kinc_mouse_set_position(int window, int x, int y);
/// <summary>
/// Gets the current mouse-position relative to a window.
/// </summary>
/// <param name="window">The window to base the returned position on</param>
/// <param name="x">A pointer where the cursor's x-position is put into</param>
/// <param name="y">A pointer where the cursor's y-position is put into</param>
KINC_FUNC void kinc_mouse_get_position(int window, int *x, int *y);
void kinc_internal_mouse_trigger_press(int window, int button, int x, int y);
void kinc_internal_mouse_trigger_release(int window, int button, int x, int y);
void kinc_internal_mouse_trigger_move(int window, int x, int y);
void kinc_internal_mouse_trigger_scroll(int window, int delta);
void kinc_internal_mouse_trigger_enter_window(int window);
void kinc_internal_mouse_trigger_leave_window(int window);
void kinc_internal_mouse_lock(int window);
void kinc_internal_mouse_unlock(void);
void kinc_internal_mouse_window_activated(int window);
void kinc_internal_mouse_window_deactivated(int window);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#undef KINC_IMPLEMENTATION
#include <kinc/window.h>
#define KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*mouse_press_callback)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/) = NULL;
static void *mouse_press_callback_data = NULL;
static void (*mouse_release_callback)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/) = NULL;
static void *mouse_release_callback_data = NULL;
static void (*mouse_move_callback)(int /*window*/, int /*x*/, int /*y*/, int /*movementX*/, int /*movementY*/, void * /*data*/) = NULL;
static void *mouse_move_callback_data = NULL;
static void (*mouse_scroll_callback)(int /*window*/, int /*delta*/, void * /*data*/) = NULL;
static void *mouse_scroll_callback_data = NULL;
static void (*mouse_enter_window_callback)(int /*window*/, void * /*data*/) = NULL;
static void *mouse_enter_window_callback_data = NULL;
static void (*mouse_leave_window_callback)(int /*window*/, void * /*data*/) = NULL;
static void *mouse_leave_window_callback_data = NULL;
void kinc_mouse_set_press_callback(void (*value)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/), void *data) {
mouse_press_callback = value;
mouse_press_callback_data = data;
}
void kinc_mouse_set_release_callback(void (*value)(int /*window*/, int /*button*/, int /*x*/, int /*y*/, void * /*data*/), void *data) {
mouse_release_callback = value;
mouse_release_callback_data = data;
}
void kinc_mouse_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, int /*movement_x*/, int /*movement_y*/, void * /*data*/), void *data) {
mouse_move_callback = value;
mouse_move_callback_data = data;
}
void kinc_mouse_set_scroll_callback(void (*value)(int /*window*/, int /*delta*/, void * /*data*/), void *data) {
mouse_scroll_callback = value;
mouse_scroll_callback_data = data;
}
void kinc_mouse_set_enter_window_callback(void (*value)(int /*window*/, void * /*data*/), void *data) {
mouse_enter_window_callback = value;
mouse_enter_window_callback_data = data;
}
void kinc_mouse_set_leave_window_callback(void (*value)(int /*window*/, void * /*data*/), void *data) {
mouse_leave_window_callback = value;
mouse_leave_window_callback_data = data;
}
void kinc_internal_mouse_trigger_release(int window, int button, int x, int y) {
if (mouse_release_callback != NULL) {
mouse_release_callback(window, button, x, y, mouse_release_callback_data);
}
}
void kinc_internal_mouse_trigger_scroll(int window, int delta) {
if (mouse_scroll_callback != NULL) {
mouse_scroll_callback(window, delta, mouse_scroll_callback_data);
}
}
void kinc_internal_mouse_trigger_enter_window(int window) {
if (mouse_enter_window_callback != NULL) {
mouse_enter_window_callback(window, mouse_enter_window_callback_data);
}
}
void kinc_internal_mouse_trigger_leave_window(int window) {
if (mouse_leave_window_callback != NULL) {
mouse_leave_window_callback(window, mouse_leave_window_callback_data);
}
}
void kinc_internal_mouse_window_activated(int window) {
if (kinc_mouse_is_locked()) {
kinc_internal_mouse_lock(window);
}
}
void kinc_internal_mouse_window_deactivated(int window) {
if (kinc_mouse_is_locked()) {
kinc_internal_mouse_unlock();
}
}
// TODO: handle state per window
static bool moved = false;
static bool locked = false;
static int preLockWindow = 0;
static int preLockX = 0;
static int preLockY = 0;
static int centerX = 0;
static int centerY = 0;
static int lastX = 0;
static int lastY = 0;
void kinc_internal_mouse_trigger_press(int window, int button, int x, int y) {
lastX = x;
lastY = y;
if (mouse_press_callback != NULL) {
mouse_press_callback(window, button, x, y, mouse_press_callback_data);
}
}
void kinc_internal_mouse_trigger_move(int window, int x, int y) {
int movementX = 0;
int movementY = 0;
if (kinc_mouse_is_locked()) {
movementX = x - centerX;
movementY = y - centerY;
if (movementX != 0 || movementY != 0) {
kinc_mouse_set_position(window, centerX, centerY);
x = centerX;
y = centerY;
}
}
else if (moved) {
movementX = x - lastX;
movementY = y - lastY;
}
moved = true;
lastX = x;
lastY = y;
if (mouse_move_callback != NULL && (movementX != 0 || movementY != 0)) {
mouse_move_callback(window, x, y, movementX, movementY, mouse_move_callback_data);
}
}
bool kinc_mouse_is_locked(void) {
return locked;
}
void kinc_mouse_lock(int window) {
if (!kinc_mouse_can_lock()) {
return;
}
locked = true;
kinc_internal_mouse_lock(window);
kinc_mouse_get_position(window, &preLockX, &preLockY);
centerX = kinc_window_width(window) / 2;
centerY = kinc_window_height(window) / 2;
kinc_mouse_set_position(window, centerX, centerY);
}
void kinc_mouse_unlock(void) {
if (!kinc_mouse_can_lock()) {
return;
}
moved = false;
locked = false;
kinc_internal_mouse_unlock();
kinc_mouse_set_position(preLockWindow, preLockX, preLockY);
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,138 @@
#pragma once
#include <kinc/global.h>
/*! \file pen.h
\brief Provides pen-support.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Sets the pen-press-callback which is called when the pen is touching the drawing-surface.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_pen_set_press_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
/// <summary>
/// Sets the pen-move-callback which is called when the pen is moved.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_pen_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
/// <summary>
/// Sets the pen-release-callback which is called when the pen is moved away from the drawing-surface.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_pen_set_release_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
/// <summary>
/// Sets the eraser-press-callback which is called when the pen is touching the drawing-surface in eraser-mode.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_eraser_set_press_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
/// <summary>
/// Sets the eraser-move-callback which is called when the pen is moved while in eraser-mode.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_eraser_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
/// <summary>
/// Sets the eraser-release-callback which is called when the pen is moved away from the drawing-surface when in eraser-mode.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_eraser_set_release_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/));
void kinc_internal_pen_trigger_move(int window, int x, int y, float pressure);
void kinc_internal_pen_trigger_press(int window, int x, int y, float pressure);
void kinc_internal_pen_trigger_release(int window, int x, int y, float pressure);
void kinc_internal_eraser_trigger_move(int window, int x, int y, float pressure);
void kinc_internal_eraser_trigger_press(int window, int x, int y, float pressure);
void kinc_internal_eraser_trigger_release(int window, int x, int y, float pressure);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*pen_press_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
static void (*pen_move_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
static void (*pen_release_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
static void (*eraser_press_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
static void (*eraser_move_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
static void (*eraser_release_callback)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/) = NULL;
void kinc_pen_set_press_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
pen_press_callback = value;
}
void kinc_pen_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
pen_move_callback = value;
}
void kinc_pen_set_release_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
pen_release_callback = value;
}
void kinc_eraser_set_press_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
eraser_press_callback = value;
}
void kinc_eraser_set_move_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
eraser_move_callback = value;
}
void kinc_eraser_set_release_callback(void (*value)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/)) {
eraser_release_callback = value;
}
void kinc_internal_pen_trigger_press(int window, int x, int y, float pressure) {
if (pen_press_callback != NULL) {
pen_press_callback(window, x, y, pressure);
}
}
void kinc_internal_pen_trigger_move(int window, int x, int y, float pressure) {
if (pen_move_callback != NULL) {
pen_move_callback(window, x, y, pressure);
}
}
void kinc_internal_pen_trigger_release(int window, int x, int y, float pressure) {
if (pen_release_callback != NULL) {
pen_release_callback(window, x, y, pressure);
}
}
void kinc_internal_eraser_trigger_press(int window, int x, int y, float pressure) {
if (eraser_press_callback != NULL) {
eraser_press_callback(window, x, y, pressure);
}
}
void kinc_internal_eraser_trigger_move(int window, int x, int y, float pressure) {
if (eraser_move_callback != NULL) {
eraser_move_callback(window, x, y, pressure);
}
}
void kinc_internal_eraser_trigger_release(int window, int x, int y, float pressure) {
if (eraser_release_callback != NULL) {
eraser_release_callback(window, x, y, pressure);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,46 @@
#pragma once
#include <kinc/global.h>
/*! \file rotation.h
\brief Provides support for rotation-sensors.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Sets the rotation-callback which is called when the device is rotated. Act quickly when this is called for a desktop-system.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_rotation_set_callback(void (*value)(float /*x*/, float /*y*/, float /*z*/));
void kinc_internal_on_rotation(float x, float y, float z);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*rotation_callback)(float /*x*/, float /*y*/, float /*z*/) = NULL;
void kinc_rotation_set_callback(void (*value)(float /*x*/, float /*y*/, float /*z*/)) {
rotation_callback = value;
}
void kinc_internal_on_rotation(float x, float y, float z) {
if (rotation_callback != NULL) {
rotation_callback(x, y, z);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,82 @@
#pragma once
#include <kinc/global.h>
/*! \file surface.h
\brief Provides touch-support.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Sets the surface-touch-start-callback which is called when a finger-touch is detected.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_surface_set_touch_start_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/));
/// <summary>
/// Sets the surface-move-callback which is called when a finger is moving around.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_surface_set_move_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/));
/// <summary>
/// Sets the surface-touch-end-callback which is called when a finger disappears. This is usually not a medical emergency.
/// </summary>
/// <param name="value">The callback</param>
KINC_FUNC void kinc_surface_set_touch_end_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/));
void kinc_internal_surface_trigger_touch_start(int index, int x, int y);
void kinc_internal_surface_trigger_move(int index, int x, int y);
void kinc_internal_surface_trigger_touch_end(int index, int x, int y);
#ifdef KINC_IMPLEMENTATION_INPUT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <memory.h>
#include <stddef.h>
static void (*surface_touch_start_callback)(int /*index*/, int /*x*/, int /*y*/) = NULL;
static void (*surface_move_callback)(int /*index*/, int /*x*/, int /*y*/) = NULL;
static void (*surface_touch_end_callback)(int /*index*/, int /*x*/, int /*y*/) = NULL;
void kinc_surface_set_touch_start_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/)) {
surface_touch_start_callback = value;
}
void kinc_surface_set_move_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/)) {
surface_move_callback = value;
}
void kinc_surface_set_touch_end_callback(void (*value)(int /*index*/, int /*x*/, int /*y*/)) {
surface_touch_end_callback = value;
}
void kinc_internal_surface_trigger_touch_start(int index, int x, int y) {
if (surface_touch_start_callback != NULL) {
surface_touch_start_callback(index, x, y);
}
}
void kinc_internal_surface_trigger_move(int index, int x, int y) {
if (surface_move_callback != NULL) {
surface_move_callback(index, x, y);
}
}
void kinc_internal_surface_trigger_touch_end(int index, int x, int y) {
if (surface_touch_end_callback != NULL) {
surface_touch_end_callback(index, x, y);
}
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,595 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
/*! \file filereader.h
\brief Provides an API very similar to fread and friends but handles the intricacies of where files are actually hidden on each supported system.
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef KINC_DEBUGDIR
#define KINC_DEBUGDIR "Deployment"
#endif
#ifdef KINC_ANDROID
struct AAsset;
struct __sFILE;
typedef struct __sFILE FILE;
#endif
#define KINC_FILE_TYPE_ASSET 0
#define KINC_FILE_TYPE_SAVE 1
typedef struct kinc_file_reader {
void *data; // A file handle or a more complex structure
size_t size;
size_t offset; // Needed by some implementations
bool (*close)(struct kinc_file_reader *reader);
size_t (*read)(struct kinc_file_reader *reader, void *data, size_t size);
size_t (*pos)(struct kinc_file_reader *reader);
bool (*seek)(struct kinc_file_reader *reader, size_t pos);
} kinc_file_reader_t;
/// <summary>
/// Opens a file for reading.
/// </summary>
/// <param name="reader">The reader to initialize for reading</param>
/// <param name="filepath">A filepath to identify a file</param>
/// <param name="type">Looks for a regular file (KINC_FILE_TYPE_ASSET) or a save-file (KINC_FILE_TYPE_SAVE)</param>
/// <returns>Whether the file could be opened</returns>
KINC_FUNC bool kinc_file_reader_open(kinc_file_reader_t *reader, const char *filepath, int type);
/// <summary>
/// Opens a memory area for reading using the file reader API.
/// </summary>
/// <param name="reader">The reader to initialize for reading</param>
/// <param name="data">A pointer to the memory area to read</param>
/// <param name="size">The size of the memory area</param>
/// <returns>This function always returns true</returns>
KINC_FUNC bool kinc_file_reader_from_memory(kinc_file_reader_t *reader, void *data, size_t size);
/// <summary>
/// Registers a file reader callback.
/// </summary>
/// <param name="callback">The function to call when opening a file</param>
KINC_FUNC void kinc_file_reader_set_callback(bool (*callback)(kinc_file_reader_t *reader, const char *filename, int type));
/// <summary>
/// Closes a file.
/// </summary>
/// <param name="reader">The file to close</param>
/// <returns>Whether the file could be closed</returns>
KINC_FUNC bool kinc_file_reader_close(kinc_file_reader_t *reader);
/// <summary>
/// Reads data from a file starting from the current reading-position and increases the reading-position accordingly.
/// </summary>
/// <param name="reader">The reader to read from</param>
/// <param name="data">A pointer to write the data to</param>
/// <param name="size">The amount of data to read in bytes</param>
/// <returns>The number of bytes that were read - can be less than size if there is not enough data in the file</returns>
KINC_FUNC size_t kinc_file_reader_read(kinc_file_reader_t *reader, void *data, size_t size);
/// <summary>
/// Figures out the size of a file.
/// </summary>
/// <param name="reader">The reader which's file-size to figure out</param>
/// <returns>The size in bytes</returns>
KINC_FUNC size_t kinc_file_reader_size(kinc_file_reader_t *reader);
/// <summary>
/// Figures out the current reading-position in the file.
/// </summary>
/// <param name="reader">The reader which's reading-position to figure out</param>
/// <returns>The current reading-position</returns>
KINC_FUNC size_t kinc_file_reader_pos(kinc_file_reader_t *reader);
/// <summary>
/// Sets the reading-position manually.
/// </summary>
/// <param name="reader">The reader which's reading-position to set</param>
/// <param name="pos">The reading-position to set</param>
/// <returns>Whether the reading position could be set</returns>
KINC_FUNC bool kinc_file_reader_seek(kinc_file_reader_t *reader, size_t pos);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a little-endian float.
/// </summary>
KINC_FUNC float kinc_read_f32le(uint8_t *data);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a big-endian float.
/// </summary>
KINC_FUNC float kinc_read_f32be(uint8_t *data);
/// <summary>
/// Interprets eight bytes starting at the provided pointer as a little-endian uint64.
/// </summary>
KINC_FUNC uint64_t kinc_read_u64le(uint8_t *data);
/// <summary>
/// Interprets eight bytes starting at the provided pointer as a big-endian uint64.
/// </summary>
KINC_FUNC uint64_t kinc_read_u64be(uint8_t *data);
/// <summary>
/// Interprets eight bytes starting at the provided pointer as a little-endian int64.
/// </summary>
KINC_FUNC int64_t kinc_read_s64le(uint8_t *data);
/// <summary>
/// Interprets eight bytes starting at the provided pointer as a big-endian int64.
/// </summary>
KINC_FUNC int64_t kinc_read_s64be(uint8_t *data);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a little-endian uint32.
/// </summary>
KINC_FUNC uint32_t kinc_read_u32le(uint8_t *data);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a big-endian uint32.
/// </summary>
KINC_FUNC uint32_t kinc_read_u32be(uint8_t *data);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a little-endian int32.
/// </summary>
KINC_FUNC int32_t kinc_read_s32le(uint8_t *data);
/// <summary>
/// Interprets four bytes starting at the provided pointer as a big-endian int32.
/// </summary>
KINC_FUNC int32_t kinc_read_s32be(uint8_t *data);
/// <summary>
/// Interprets two bytes starting at the provided pointer as a little-endian uint16.
/// </summary>
KINC_FUNC uint16_t kinc_read_u16le(uint8_t *data);
/// <summary>
/// Interprets two bytes starting at the provided pointer as a big-endian uint16.
/// </summary>
KINC_FUNC uint16_t kinc_read_u16be(uint8_t *data);
/// <summary>
/// Interprets two bytes starting at the provided pointer as a little-endian int16.
/// </summary>
KINC_FUNC int16_t kinc_read_s16le(uint8_t *data);
/// <summary>
/// Interprets two bytes starting at the provided pointer as a big-endian int16.
/// </summary>
KINC_FUNC int16_t kinc_read_s16be(uint8_t *data);
/// <summary>
/// Interprets one byte starting at the provided pointer as a uint8.
/// </summary>
KINC_FUNC uint8_t kinc_read_u8(uint8_t *data);
/// <summary>
/// Interprets one byte starting at the provided pointer as an int8.
/// </summary>
KINC_FUNC int8_t kinc_read_s8(uint8_t *data);
void kinc_internal_set_files_location(char *dir);
char *kinc_internal_get_files_location(void);
bool kinc_internal_file_reader_callback(kinc_file_reader_t *reader, const char *filename, int type);
bool kinc_internal_file_reader_open(kinc_file_reader_t *reader, const char *filename, int type);
#ifdef KINC_IMPLEMENTATION_IO
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include "filereader.h"
#undef KINC_IMPLEMENTATION
#include <kinc/system.h>
#define KINC_IMPLEMENTATION
#ifdef KINC_ANDROID
#include <kinc/backend/Android.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef KINC_WINDOWS
#include <malloc.h>
#include <memory.h>
#endif
static bool memory_close_callback(kinc_file_reader_t *reader) {
return true;
}
static size_t memory_read_callback(kinc_file_reader_t *reader, void *data, size_t size) {
size_t read_size = reader->size - reader->offset < size ? reader->size - reader->offset : size;
memcpy(data, (uint8_t *)reader->data + reader->offset, read_size);
reader->offset += read_size;
return read_size;
}
static size_t memory_pos_callback(kinc_file_reader_t *reader) {
return reader->offset;
}
static bool memory_seek_callback(kinc_file_reader_t *reader, size_t pos) {
reader->offset = pos;
return true;
}
bool kinc_file_reader_from_memory(kinc_file_reader_t *reader, void *data, size_t size)
{
memset(reader, 0, sizeof(kinc_file_reader_t));
reader->data = data;
reader->size = size;
reader->read = memory_read_callback;
reader->pos = memory_pos_callback;
reader->seek = memory_seek_callback;
reader->close = memory_close_callback;
return true;
}
#ifdef KINC_IOS
const char *iphonegetresourcepath(void);
#endif
#ifdef KINC_MACOS
const char *macgetresourcepath(void);
#endif
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
#include <kinc/backend/MiniWindows.h>
#endif
#ifdef KINC_RASPBERRY_PI
#define KINC_LINUX
#endif
static char *fileslocation = NULL;
static bool (*file_reader_callback)(kinc_file_reader_t *reader, const char *filename, int type) = NULL;
#ifdef KINC_WINDOWS
static wchar_t wfilepath[1001];
#endif
void kinc_internal_set_files_location(char *dir) {
fileslocation = dir;
}
char *kinc_internal_get_files_location(void) {
return fileslocation;
}
bool kinc_internal_file_reader_callback(kinc_file_reader_t *reader, const char *filename, int type) {
return file_reader_callback ? file_reader_callback(reader, filename, type) : false;
}
#ifdef KINC_WINDOWSAPP
void kinc_internal_uwp_installed_location_path(char *path);
#endif
#if defined(KINC_WINDOWS)
static size_t kinc_libc_file_reader_read(kinc_file_reader_t *reader, void *data, size_t size) {
DWORD readBytes = 0;
if (ReadFile(reader->data, data, (DWORD)size, &readBytes, NULL)) {
return (size_t)readBytes;
}
else {
return 0;
}
}
static bool kinc_libc_file_reader_seek(kinc_file_reader_t *reader, size_t pos) {
// TODO: make this 64-bit compliant
SetFilePointer(reader->data, (LONG)pos, NULL, FILE_BEGIN);
return true;
}
static bool kinc_libc_file_reader_close(kinc_file_reader_t *reader) {
CloseHandle(reader->data);
return true;
}
static size_t kinc_libc_file_reader_pos(kinc_file_reader_t *reader) {
// TODO: make this 64-bit compliant
return (size_t)SetFilePointer(reader->data, 0, NULL, FILE_CURRENT);
}
#else
static size_t kinc_libc_file_reader_read(kinc_file_reader_t *reader, void *data, size_t size) {
return fread(data, 1, size, (FILE *)reader->data);
}
static bool kinc_libc_file_reader_seek(kinc_file_reader_t *reader, size_t pos) {
fseek((FILE *)reader->data, pos, SEEK_SET);
return true;
}
static bool kinc_libc_file_reader_close(kinc_file_reader_t *reader) {
if (reader->data != NULL) {
fclose((FILE *)reader->data);
reader->data = NULL;
}
return true;
}
static size_t kinc_libc_file_reader_pos(kinc_file_reader_t *reader) {
return ftell((FILE *)reader->data);
}
#endif
bool kinc_internal_file_reader_open(kinc_file_reader_t *reader, const char *filename, int type) {
char filepath[1001];
#ifdef KINC_IOS
strcpy(filepath, type == KINC_FILE_TYPE_SAVE ? kinc_internal_save_path() : iphonegetresourcepath());
if (type != KINC_FILE_TYPE_SAVE) {
strcat(filepath, "/");
strcat(filepath, KINC_DEBUGDIR);
strcat(filepath, "/");
}
strcat(filepath, filename);
#endif
#ifdef KINC_MACOS
strcpy(filepath, type == KINC_FILE_TYPE_SAVE ? kinc_internal_save_path() : macgetresourcepath());
if (type != KINC_FILE_TYPE_SAVE) {
strcat(filepath, "/");
strcat(filepath, KINC_DEBUGDIR);
strcat(filepath, "/");
}
strcat(filepath, filename);
#endif
#ifdef KINC_WINDOWS
if (type == KINC_FILE_TYPE_SAVE) {
strcpy(filepath, kinc_internal_save_path());
strcat(filepath, filename);
}
else {
strcpy(filepath, filename);
}
size_t filepathlength = strlen(filepath);
for (size_t i = 0; i < filepathlength; ++i)
if (filepath[i] == '/')
filepath[i] = '\\';
#endif
#ifdef KINC_WINDOWSAPP
kinc_internal_uwp_installed_location_path(filepath);
strcat(filepath, "\\");
strcat(filepath, filename);
#endif
#if defined(KINC_LINUX) || defined(KINC_ANDROID)
if (type == KINC_FILE_TYPE_SAVE) {
strcpy(filepath, kinc_internal_save_path());
strcat(filepath, filename);
}
else {
strcpy(filepath, filename);
}
#endif
#ifdef KINC_WASM
strcpy(filepath, filename);
#endif
#ifdef KINC_EMSCRIPTEN
strcpy(filepath, KINC_DEBUGDIR);
strcat(filepath, "/");
strcat(filepath, filename);
#endif
#ifdef KINC_WINDOWS
// Drive letter or network
bool isAbsolute = (filename[1] == ':' && filename[2] == '\\') || (filename[0] == '\\' && filename[1] == '\\');
#else
bool isAbsolute = filename[0] == '/';
#endif
if (isAbsolute) {
strcpy(filepath, filename);
}
else if (fileslocation != NULL && type != KINC_FILE_TYPE_SAVE) {
strcpy(filepath, fileslocation);
strcat(filepath, "/");
strcat(filepath, filename);
}
#ifdef KINC_WINDOWS
MultiByteToWideChar(CP_UTF8, 0, filepath, -1, wfilepath, 1000);
reader->data = CreateFileW(wfilepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (reader->data == INVALID_HANDLE_VALUE) {
return false;
}
#else
reader->data = fopen(filepath, "rb");
if (reader->data == NULL) {
return false;
}
#endif
#ifdef KINC_WINDOWS
// TODO: make this 64-bit compliant
reader->size = (size_t)GetFileSize(reader->data, NULL);
#else
fseek((FILE *)reader->data, 0, SEEK_END);
reader->size = ftell((FILE *)reader->data);
fseek((FILE *)reader->data, 0, SEEK_SET);
#endif
reader->read = kinc_libc_file_reader_read;
reader->seek = kinc_libc_file_reader_seek;
reader->close = kinc_libc_file_reader_close;
reader->pos = kinc_libc_file_reader_pos;
return true;
}
#if !defined(KINC_ANDROID) && !defined(KINC_CONSOLE)
bool kinc_file_reader_open(kinc_file_reader_t *reader, const char *filename, int type) {
memset(reader, 0, sizeof(*reader));
return kinc_internal_file_reader_callback(reader, filename, type) ||
kinc_internal_file_reader_open(reader, filename, type);
}
#endif
void kinc_file_reader_set_callback(bool (*callback)(kinc_file_reader_t *reader, const char *filename, int type)) {
file_reader_callback = callback;
}
size_t kinc_file_reader_read(kinc_file_reader_t *reader, void *data, size_t size) {
return reader->read(reader, data, size);
}
bool kinc_file_reader_seek(kinc_file_reader_t *reader, size_t pos) {
return reader->seek(reader, pos);
}
bool kinc_file_reader_close(kinc_file_reader_t *reader) {
return reader->close(reader);
}
size_t kinc_file_reader_pos(kinc_file_reader_t *reader) {
return reader->pos(reader);
}
size_t kinc_file_reader_size(kinc_file_reader_t *reader) {
return reader->size;
}
float kinc_read_f32le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN // speed optimization
return *(float *)data;
#else // works on all architectures
int i = (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
return *(float *)&i;
#endif
}
float kinc_read_f32be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN // speed optimization
return *(float *)data;
#else // works on all architectures
int i = (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
return *(float *)&i;
#endif
}
uint64_t kinc_read_u64le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(uint64_t *)data;
#else
return ((uint64_t)data[0] << 0) | ((uint64_t)data[1] << 8) | ((uint64_t)data[2] << 16) | ((uint64_t)data[3] << 24) | ((uint64_t)data[4] << 32) |
((uint64_t)data[5] << 40) | ((uint64_t)data[6] << 48) | ((uint64_t)data[7] << 56);
#endif
}
uint64_t kinc_read_u64be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(uint64_t *)data;
#else
return ((uint64_t)data[7] << 0) | ((uint64_t)data[6] << 8) | ((uint64_t)data[5] << 16) | ((uint64_t)data[4] << 24) | ((uint64_t)data[3] << 32) |
((uint64_t)data[2] << 40) | ((uint64_t)data[1] << 48) | ((uint64_t)data[0] << 56);
#endif
}
int64_t kinc_read_s64le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(int64_t *)data;
#else
return ((int64_t)data[0] << 0) | ((int64_t)data[1] << 8) | ((int64_t)data[2] << 16) | ((int64_t)data[3] << 24) | ((int64_t)data[4] << 32) |
((int64_t)data[5] << 40) | ((int64_t)data[6] << 48) | ((int64_t)data[7] << 56);
#endif
}
int64_t kinc_read_s64be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(int64_t *)data;
#else
return ((int64_t)data[7] << 0) | ((int64_t)data[6] << 8) | ((int64_t)data[5] << 16) | ((int64_t)data[4] << 24) | ((int64_t)data[3] << 32) |
((int64_t)data[2] << 40) | ((int64_t)data[1] << 48) | ((int64_t)data[0] << 56);
#endif
}
uint32_t kinc_read_u32le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(uint32_t *)data;
#else
return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
#endif
}
uint32_t kinc_read_u32be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(uint32_t *)data;
#else
return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
#endif
}
int32_t kinc_read_s32le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(int32_t *)data;
#else
return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
#endif
}
int32_t kinc_read_s32be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(int32_t *)data;
#else
return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
#endif
}
uint16_t kinc_read_u16le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(uint16_t *)data;
#else
return (data[0] << 0) | (data[1] << 8);
#endif
}
uint16_t kinc_read_u16be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(uint16_t *)data;
#else
return (data[1] << 0) | (data[0] << 8);
#endif
}
int16_t kinc_read_s16le(uint8_t *data) {
#ifdef KINC_LITTLE_ENDIAN
return *(int16_t *)data;
#else
return (data[0] << 0) | (data[1] << 8);
#endif
}
int16_t kinc_read_s16be(uint8_t *data) {
#ifdef KINC_BIG_ENDIAN
return *(int16_t *)data;
#else
return (data[1] << 0) | (data[0] << 8);
#endif
}
uint8_t kinc_read_u8(uint8_t *data) {
return *data;
}
int8_t kinc_read_s8(uint8_t *data) {
return *(int8_t *)data;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,132 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
/*! \file filewriter.h
\brief Provides an API very similar to fwrite and friends but uses a directory that can actually used for persistent file storage. This can later be read
using the kinc_file_reader-functions and KINC_FILE_TYPE_SAVE.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_file_writer {
void *file;
const char *filename;
bool mounted;
} kinc_file_writer_t;
/// <summary>
/// Opens a file for writing.
/// </summary>
/// <param name="reader">The writer to initialize for writing</param>
/// <param name="filepath">A filepath to identify a file</param>
/// <returns>Whether the file could be opened</returns>
KINC_FUNC bool kinc_file_writer_open(kinc_file_writer_t *writer, const char *filepath);
/// <summary>
/// Writes data to a file starting from the current writing-position and increases the writing-position accordingly.
/// </summary>
/// <param name="reader">The writer to write to</param>
/// <param name="data">A pointer to read the data from</param>
/// <param name="size">The amount of data to write in bytes</param>
KINC_FUNC void kinc_file_writer_write(kinc_file_writer_t *writer, void *data, int size);
/// <summary>
/// Closes a file.
/// </summary>
/// <param name="reader">The file to close</param>
KINC_FUNC void kinc_file_writer_close(kinc_file_writer_t *writer);
#ifdef KINC_IMPLEMENTATION_IO
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#if !defined(KINC_CONSOLE)
#include "filewriter.h"
#undef KINC_IMPLEMENTATION
#include <kinc/error.h>
#include <kinc/log.h>
#include <kinc/system.h>
#define KINC_IMPLEMENTATION
#include <stdio.h>
#include <string.h>
#if defined(KINC_WINDOWS)
#include <kinc/backend/MiniWindows.h>
#endif
#if defined(KINC_PS4) || defined(KINC_SWITCH)
#define MOUNT_SAVES
bool mountSaveData(bool);
void unmountSaveData();
#endif
bool kinc_file_writer_open(kinc_file_writer_t *writer, const char *filepath) {
writer->file = NULL;
writer->mounted = false;
#ifdef MOUNT_SAVES
if (!mountSaveData(true)) {
return false;
}
writer->mounted = true;
#endif
char path[1001];
strcpy(path, kinc_internal_save_path());
strcat(path, filepath);
#ifdef KINC_WINDOWS
wchar_t wpath[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wpath, MAX_PATH);
writer->file = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
#else
writer->file = fopen(path, "wb");
#endif
if (writer->file == NULL) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Could not open file %s.", filepath);
return false;
}
return true;
}
void kinc_file_writer_close(kinc_file_writer_t *writer) {
if (writer->file != NULL) {
#ifdef KINC_WINDOWS
CloseHandle(writer->file);
#else
fclose((FILE *)writer->file);
#endif
writer->file = NULL;
}
#ifdef MOUNT_SAVES
if (writer->mounted) {
writer->mounted = false;
unmountSaveData();
}
#endif
}
void kinc_file_writer_write(kinc_file_writer_t *writer, void *data, int size) {
#ifdef KINC_WINDOWS
DWORD written = 0;
WriteFile(writer->file, data, (DWORD)size, &written, NULL);
#else
fwrite(data, 1, size, (FILE *)writer->file);
#endif
}
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
#define KINC_IMPLEMENTATION_IO
#include "filereader.h"
#include "filewriter.h"

View File

@ -0,0 +1,24 @@
LZ4 Library
Copyright (c) 2011-2016, Yann Collet
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,463 @@
/*
* LZ4 - Fast LZ compression algorithm
* Header File
* Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 homepage : http://www.lz4.org
- LZ4 source repository : https://github.com/lz4/lz4
*/
#ifndef LZ4_H_2983827168210
#define LZ4_H_2983827168210
#if defined (__cplusplus)
extern "C" {
#endif
/* --- Dependency --- */
#include <stddef.h> /* size_t */
/**
Introduction
LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core,
scalable with multi-cores CPU. It features an extremely fast decoder, with speed in
multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
The LZ4 compression library provides in-memory compression and decompression functions.
Compression can be done in:
- a single step (described as Simple Functions)
- a single step, reusing a context (described in Advanced Functions)
- unbounded multiple steps (described as Streaming compression)
lz4.h provides block compression functions. It gives full buffer control to user.
Decompressing an lz4-compressed block also requires metadata (such as compressed size).
Each application is free to encode such metadata in whichever way it wants.
An additional format, called LZ4 frame specification (doc/lz4_Frame_format.md),
take care of encoding standard metadata alongside LZ4-compressed blocks.
If your application requires interoperability, it's recommended to use it.
A library is provided to take care of it, see lz4frame.h.
*/
/*^***************************************************************
* Export parameters
*****************************************************************/
/*
* LZ4_DLL_EXPORT :
* Enable exporting of functions when building a Windows DLL
*/
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
# define LZ4LIB_API __declspec(dllexport)
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
# define LZ4LIB_API __declspec(dllimport) /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/
#else
# define LZ4LIB_API
#endif
/*========== Version =========== */
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
#define LZ4_QUOTE(str) #str
#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
LZ4LIB_API int LZ4_versionNumber (void);
LZ4LIB_API const char* LZ4_versionString (void);
/*-************************************
* Tuning parameter
**************************************/
/*!
* LZ4_MEMORY_USAGE :
* Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
* Increasing memory usage improves compression ratio
* Reduced memory usage can improve speed, due to cache effect
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
*/
#define LZ4_MEMORY_USAGE 14
/*-************************************
* Simple Functions
**************************************/
/*! LZ4_compress_default() :
Compresses 'sourceSize' bytes from buffer 'source'
into already allocated 'dest' buffer of size 'maxDestSize'.
Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
It also runs faster, so it's a recommended setting.
If the function cannot compress 'source' into a more limited 'dest' budget,
compression stops *immediately*, and the function result is zero.
As a consequence, 'dest' content is not valid.
This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
or 0 if compression fails */
LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
/*! LZ4_decompress_safe() :
compressedSize : is the precise full size of the compressed block.
maxDecompressedSize : is the size of destination buffer, which must be already allocated.
return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
If destination buffer is not large enough, decoding will stop and output an error code (<0).
If the source stream is detected malformed, the function will stop decoding and return a negative result.
This function is protected against buffer overflow exploits, including malicious data packets.
It never writes outside output buffer, nor reads outside input buffer.
*/
LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
/*-************************************
* Advanced Functions
**************************************/
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
/*!
LZ4_compressBound() :
Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
This function is primarily useful for memory allocation purposes (destination buffer size).
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
inputSize : max supported value is LZ4_MAX_INPUT_SIZE
return : maximum output size in a "worst case" scenario
or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
*/
LZ4LIB_API int LZ4_compressBound(int inputSize);
/*!
LZ4_compress_fast() :
Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
An acceleration value of "1" is the same as regular LZ4_compress_default()
Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
*/
LZ4LIB_API int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
/*!
LZ4_compress_fast_extState() :
Same compression function, just using an externally allocated memory space to store compression state.
Use LZ4_sizeofState() to know how much memory must be allocated,
and allocate it on 8-bytes boundaries (using malloc() typically).
Then, provide it as 'void* state' to compression function.
*/
LZ4LIB_API int LZ4_sizeofState(void);
LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
/*!
LZ4_compress_destSize() :
Reverse the logic, by compressing as much data as possible from 'source' buffer
into already allocated buffer 'dest' of size 'targetDestSize'.
This function either compresses the entire 'source' content into 'dest' if it's large enough,
or fill 'dest' buffer completely with as much data as possible from 'source'.
*sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
New value is necessarily <= old value.
return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
or 0 if compression fails
*/
LZ4LIB_API int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
/*!
LZ4_decompress_fast() :
originalSize : is the original and therefore uncompressed size
return : the number of bytes read from the source buffer (in other words, the compressed size)
If the source stream is detected malformed, the function will stop decoding and return a negative result.
Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
note : This function fully respect memory boundaries for properly formed compressed data.
It is a bit faster than LZ4_decompress_safe().
However, it does not provide any protection against intentionally modified data stream (malicious input).
Use this function in trusted environment only (data to decode comes from a trusted source).
*/
LZ4LIB_API int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
/*!
LZ4_decompress_safe_partial() :
This function decompress a compressed block of size 'compressedSize' at position 'source'
into destination buffer 'dest' of size 'maxDecompressedSize'.
The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
reducing decompression time.
return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
Always control how many bytes were decoded.
If the source stream is detected malformed, the function will stop decoding and return a negative result.
This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
*/
LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
/*-*********************************************
* Streaming Compression Functions
***********************************************/
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
/*! LZ4_createStream() and LZ4_freeStream() :
* LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure.
* LZ4_freeStream() releases its memory.
*/
LZ4LIB_API LZ4_stream_t* LZ4_createStream(void);
LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr);
/*! LZ4_resetStream() :
* An LZ4_stream_t structure can be allocated once and re-used multiple times.
* Use this function to init an allocated `LZ4_stream_t` structure and start a new compression.
*/
LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);
/*! LZ4_loadDict() :
* Use this function to load a static dictionary into LZ4_stream.
* Any previous data will be forgotten, only 'dictionary' will remain in memory.
* Loading a size of 0 is allowed.
* Return : dictionary size, in bytes (necessarily <= 64 KB)
*/
LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
/*! LZ4_compress_fast_continue() :
* Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
* Important : Previous data blocks are assumed to still be present and unmodified !
* 'dst' buffer must be already allocated.
* If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
* If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
*/
LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
/*! LZ4_saveDict() :
* If previously compressed data block is not guaranteed to remain available at its memory location,
* save it into a safer place (char* safeBuffer).
* Note : you don't need to call LZ4_loadDict() afterwards,
* dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue().
* Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.
*/
LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
/*-**********************************************
* Streaming Decompression Functions
* Bufferless synchronous API
************************************************/
typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* incomplete type (defined later) */
/* creation / destruction of streaming decompression tracking structure */
LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);
LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
/*! LZ4_setStreamDecode() :
* Use this function to instruct where to find the dictionary.
* Setting a size of 0 is allowed (same effect as reset).
* @return : 1 if OK, 0 if error
*/
LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
/*!
LZ4_decompress_*_continue() :
These decoding functions allow decompression of multiple blocks in "streaming" mode.
Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
In the case of a ring buffers, decoding buffer must be either :
- Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
- Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
In which case, encoding and decoding buffers do not need to be synchronized,
and encoding ring buffer can have any size, including small ones ( < 64 KB).
- _At least_ 64 KB + 8 bytes + maxBlockSize.
In which case, encoding and decoding buffers do not need to be synchronized,
and encoding ring buffer can have any size, including larger than decoding buffer.
Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
and indicate where it is saved using LZ4_setStreamDecode()
*/
LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
/*! LZ4_decompress_*_usingDict() :
* These decoding functions work the same as
* a combination of LZ4_setStreamDecode() followed by LZ4_decompress_*_continue()
* They are stand-alone, and don't need an LZ4_streamDecode_t structure.
*/
LZ4LIB_API int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
/*^**********************************************
* !!!!!! STATIC LINKING ONLY !!!!!!
***********************************************/
/*-************************************
* Private definitions
**************************************
* Do not use these definitions.
* They are exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.
* Using these definitions will expose code to API and/or ABI break in future versions of the library.
**************************************/
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
#include <stdint.h>
typedef struct {
uint32_t hashTable[LZ4_HASH_SIZE_U32];
uint32_t currentOffset;
uint32_t initCheck;
const uint8_t* dictionary;
uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */
uint32_t dictSize;
} LZ4_stream_t_internal;
typedef struct {
const uint8_t* externalDict;
size_t extDictSize;
const uint8_t* prefixEnd;
size_t prefixSize;
} LZ4_streamDecode_t_internal;
#else
typedef struct {
unsigned int hashTable[LZ4_HASH_SIZE_U32];
unsigned int currentOffset;
unsigned int initCheck;
const unsigned char* dictionary;
unsigned char* bufferStart; /* obsolete, used for slideInputBuffer */
unsigned int dictSize;
} LZ4_stream_t_internal;
typedef struct {
const unsigned char* externalDict;
size_t extDictSize;
const unsigned char* prefixEnd;
size_t prefixSize;
} LZ4_streamDecode_t_internal;
#endif
/*!
* LZ4_stream_t :
* information structure to track an LZ4 stream.
* init this structure before first use.
* note : only use in association with static linking !
* this definition is not API/ABI safe,
* and may change in a future version !
*/
#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))
union LZ4_stream_u {
unsigned long long table[LZ4_STREAMSIZE_U64];
LZ4_stream_t_internal internal_donotuse;
} ; /* previously typedef'd to LZ4_stream_t */
/*!
* LZ4_streamDecode_t :
* information structure to track an LZ4 stream during decompression.
* init this structure using LZ4_setStreamDecode (or memset()) before first use
* note : only use in association with static linking !
* this definition is not API/ABI safe,
* and may change in a future version !
*/
#define LZ4_STREAMDECODESIZE_U64 4
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
union LZ4_streamDecode_u {
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
LZ4_streamDecode_t_internal internal_donotuse;
} ; /* previously typedef'd to LZ4_streamDecode_t */
/*=************************************
* Obsolete Functions
**************************************/
/* Deprecation warnings */
/* Should these warnings be a problem,
it is generally possible to disable them,
typically with -Wno-deprecated-declarations for gcc
or _CRT_SECURE_NO_WARNINGS in Visual.
Otherwise, it's also possible to define LZ4_DISABLE_DEPRECATE_WARNINGS */
#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS
# define LZ4_DEPRECATED(message) /* disable deprecation warnings */
#else
# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */
# define LZ4_DEPRECATED(message) [[deprecated(message)]]
# elif (LZ4_GCC_VERSION >= 405) || defined(__clang__)
# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
# elif (LZ4_GCC_VERSION >= 301)
# define LZ4_DEPRECATED(message) __attribute__((deprecated))
# elif defined(_MSC_VER)
# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
# else
# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
# define LZ4_DEPRECATED(message)
# endif
#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */
/* Obsolete compression functions */
LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress (const char* source, char* dest, int sourceSize);
LZ4_DEPRECATED("use LZ4_compress_default() instead") int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
/* Obsolete decompression functions */
/* These function names are completely deprecated and must no longer be used.
They are only provided in lz4.c for compatibility with older programs.
- LZ4_uncompress is the same as LZ4_decompress_fast
- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
These function prototypes are now disabled; uncomment them only if you really need them.
It is highly recommended to stop using these prototypes and migrate to maintained ones */
/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
/* Obsolete streaming functions; use new streaming interface whenever possible */
LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer);
LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state);
/* Obsolete streaming decoding functions */
LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
#if defined (__cplusplus)
}
#endif
#endif /* LZ4_H_2983827168210 */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
/*
LZ4 auto-framing library
Header File
Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 source repository : https://github.com/lz4/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
/* LZ4F is a stand-alone API to create LZ4-compressed frames
* conformant with specification v1.5.1.
* It also offers streaming capabilities.
* lz4.h is not required when using lz4frame.h.
* */
#ifndef LZ4F_H_09782039843
#define LZ4F_H_09782039843
#if defined (__cplusplus)
extern "C" {
#endif
/* --- Dependency --- */
#include <stddef.h> /* size_t */
/*-***************************************************************
* Compiler specifics
*****************************************************************/
/*!
* LZ4_DLL_EXPORT :
* Enable exporting of functions when building a Windows DLL
*/
#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)
# define LZ4FLIB_API __declspec(dllexport)
#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)
# define LZ4FLIB_API __declspec(dllimport)
#else
# define LZ4FLIB_API
#endif
#if defined(_MSC_VER)
# define LZ4F_DEPRECATE(x) x /* __declspec(deprecated) x - only works with C++ */
#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
# define LZ4F_DEPRECATE(x) x __attribute__((deprecated))
#else
# define LZ4F_DEPRECATE(x) x /* no deprecation warning for this compiler */
#endif
/*-************************************
* Error management
**************************************/
typedef size_t LZ4F_errorCode_t;
LZ4FLIB_API unsigned LZ4F_isError(LZ4F_errorCode_t code);
LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return error code string; useful for debugging */
/*-************************************
* Frame compression types
**************************************/
/* #define LZ4F_DISABLE_OBSOLETE_ENUMS */ /* uncomment to disable obsolete enums */
#ifndef LZ4F_DISABLE_OBSOLETE_ENUMS
# define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x
#else
# define LZ4F_OBSOLETE_ENUM(x)
#endif
typedef enum {
LZ4F_default=0,
LZ4F_max64KB=4,
LZ4F_max256KB=5,
LZ4F_max1MB=6,
LZ4F_max4MB=7
LZ4F_OBSOLETE_ENUM(max64KB)
LZ4F_OBSOLETE_ENUM(max256KB)
LZ4F_OBSOLETE_ENUM(max1MB)
LZ4F_OBSOLETE_ENUM(max4MB)
} LZ4F_blockSizeID_t;
typedef enum {
LZ4F_blockLinked=0,
LZ4F_blockIndependent
LZ4F_OBSOLETE_ENUM(blockLinked)
LZ4F_OBSOLETE_ENUM(blockIndependent)
} LZ4F_blockMode_t;
typedef enum {
LZ4F_noContentChecksum=0,
LZ4F_contentChecksumEnabled
LZ4F_OBSOLETE_ENUM(noContentChecksum)
LZ4F_OBSOLETE_ENUM(contentChecksumEnabled)
} LZ4F_contentChecksum_t;
typedef enum {
LZ4F_frame=0,
LZ4F_skippableFrame
LZ4F_OBSOLETE_ENUM(skippableFrame)
} LZ4F_frameType_t;
#ifndef LZ4F_DISABLE_OBSOLETE_ENUMS
typedef LZ4F_blockSizeID_t blockSizeID_t;
typedef LZ4F_blockMode_t blockMode_t;
typedef LZ4F_frameType_t frameType_t;
typedef LZ4F_contentChecksum_t contentChecksum_t;
#endif
/* LZ4F_frameInfo_t :
* makes it possible to supply detailed frame parameters to the stream interface.
* It's not required to set all fields, as long as the structure was initially memset() to zero.
* All reserved fields must be set to zero. */
typedef struct {
LZ4F_blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB ; 0 == default */
LZ4F_blockMode_t blockMode; /* blockLinked, blockIndependent ; 0 == default */
LZ4F_contentChecksum_t contentChecksumFlag; /* noContentChecksum, contentChecksumEnabled ; 0 == default */
LZ4F_frameType_t frameType; /* LZ4F_frame, skippableFrame ; 0 == default */
unsigned long long contentSize; /* Size of uncompressed (original) content ; 0 == unknown */
unsigned reserved[2]; /* must be zero for forward compatibility */
} LZ4F_frameInfo_t;
/* LZ4F_preferences_t :
* makes it possible to supply detailed compression parameters to the stream interface.
* It's not required to set all fields, as long as the structure was initially memset() to zero.
* All reserved fields must be set to zero. */
typedef struct {
LZ4F_frameInfo_t frameInfo;
int compressionLevel; /* 0 == default (fast mode); values above 16 count as 16; values below 0 count as 0 */
unsigned autoFlush; /* 1 == always flush (reduce usage of tmp buffer) */
unsigned reserved[4]; /* must be zero for forward compatibility */
} LZ4F_preferences_t;
/*-*********************************
* Simple compression function
***********************************/
/*!LZ4F_compressFrameBound() :
* Returns the maximum possible size of a frame compressed with LZ4F_compressFrame() given srcSize content and preferences.
* Note : this result is only usable with LZ4F_compressFrame(), not with multi-segments compression.
*/
LZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
/*!LZ4F_compressFrame() :
* Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.5.1
* An important rule is that dstBuffer MUST be large enough (dstCapacity) to store the result in worst case situation.
* This value is supplied by LZ4F_compressFrameBound().
* If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode).
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
* @return : number of bytes written into dstBuffer.
* or an error code if it fails (can be tested using LZ4F_isError())
*/
LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
/*-***********************************
* Advanced compression functions
*************************************/
typedef struct LZ4F_cctx_s LZ4F_cctx; /* incomplete type */
typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with previous API version */
typedef struct {
unsigned stableSrc; /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */
unsigned reserved[3];
} LZ4F_compressOptions_t;
/* Resource Management */
#define LZ4F_VERSION 100
LZ4FLIB_API unsigned LZ4F_getVersion(void);
LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version);
LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
/* LZ4F_createCompressionContext() :
* The first thing to do is to create a compressionContext object, which will be used in all compression operations.
* This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.
* The function will provide a pointer to a fully allocated LZ4F_cctx object.
* If @return != zero, there was an error during context creation.
* Object can release its memory using LZ4F_freeCompressionContext();
*/
/* Compression */
#define LZ4F_HEADER_SIZE_MAX 15
LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* prefsPtr);
/* LZ4F_compressBegin() :
* will write the frame header into dstBuffer.
* dstCapacity must be large enough to store the header. Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
* `prefsPtr` is optional : you can provide NULL as argument, all preferences will then be set to default.
* @return : number of bytes written into dstBuffer for the header
* or an error code (which can be tested using LZ4F_isError())
*/
LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr);
/* LZ4F_compressBound() :
* Provides dstCapacity given a srcSize to guarantee operation success in worst case situations.
* prefsPtr is optional : you can provide NULL as argument, preferences will be set to cover worst case scenario.
* Result is always the same for a srcSize and prefsPtr, so it can be trusted to size reusable buffers.
* When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations.
*/
LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* cOptPtr);
/* LZ4F_compressUpdate() :
* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
* An important rule is that dstCapacity MUST be large enough to ensure operation success even in worst case situations.
* This value is provided by LZ4F_compressBound().
* If this condition is not respected, LZ4F_compress() will fail (result is an errorCode).
* LZ4F_compressUpdate() doesn't guarantee error recovery. When an error occurs, compression context must be freed or resized.
* `cOptPtr` is optional : NULL can be provided, in which case all options are set to default.
* @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered).
* or an error code if it fails (which can be tested using LZ4F_isError())
*/
LZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* cOptPtr);
/* LZ4F_flush() :
* When data must be generated and sent immediately, without waiting for a block to be completely filled,
* it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx.
* `dstCapacity` must be large enough to ensure the operation will be successful.
* `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default.
* @return : number of bytes written into dstBuffer (it can be zero, which means there was no data stored within cctx)
* or an error code if it fails (which can be tested using LZ4F_isError())
*/
LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* cOptPtr);
/* LZ4F_compressEnd() :
* To properly finish an LZ4 frame, invoke LZ4F_compressEnd().
* It will flush whatever data remained within `cctx` (like LZ4_flush())
* and properly finalize the frame, with an endMark and a checksum.
* `cOptPtr` is optional : NULL can be provided, in which case all options will be set to default.
* @return : number of bytes written into dstBuffer (necessarily >= 4 (endMark), or 8 if optional frame checksum is enabled)
* or an error code if it fails (which can be tested using LZ4F_isError())
* A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task.
*/
/*-*********************************
* Decompression functions
***********************************/
typedef struct LZ4F_dctx_s LZ4F_dctx; /* incomplete type */
typedef LZ4F_dctx* LZ4F_decompressionContext_t; /* compatibility with previous API versions */
typedef struct {
unsigned stableDst; /* guarantee that decompressed data will still be there on next function calls (avoid storage into tmp buffers) */
unsigned reserved[3];
} LZ4F_decompressOptions_t;
/* Resource management */
/*!LZ4F_createDecompressionContext() :
* Create an LZ4F_decompressionContext_t object, which will be used to track all decompression operations.
* The version provided MUST be LZ4F_VERSION. It is intended to track potential breaking differences between different versions.
* The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext_t object.
* The result is an errorCode, which can be tested using LZ4F_isError().
* dctx memory can be released using LZ4F_freeDecompressionContext();
* The result of LZ4F_freeDecompressionContext() is indicative of the current state of decompressionContext when being released.
* That is, it should be == 0 if decompression has been completed fully and correctly.
*/
LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version);
LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctx);
/*====== Decompression ======*/
/*!LZ4F_getFrameInfo() :
* This function decodes frame header information (such as max blockSize, frame checksum, etc.).
* Its usage is optional. The objective is to extract frame header information, typically for allocation purposes.
* A header size is variable and can length from 7 to 15 bytes. It's possible to provide more input bytes than that.
* The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value).
* Decompression must resume from this point (srcBuffer + *srcSizePtr).
* Note that LZ4F_getFrameInfo() can also be used anytime *after* decompression is started, in which case 0 input byte can be enough.
* Frame header info is *copied into* an already allocated LZ4F_frameInfo_t structure.
* @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call,
* or an error code which can be tested using LZ4F_isError()
* (typically, when there is not enough src bytes to fully decode the frame header)
*/
LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
LZ4F_frameInfo_t* frameInfoPtr,
const void* srcBuffer, size_t* srcSizePtr);
/*!LZ4F_decompress() :
* Call this function repetitively to regenerate data compressed within `srcBuffer`.
* The function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *dstSizePtr.
*
* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
*
* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
* Number of bytes read can be < number of bytes provided, meaning there is some more data to decode.
* It typically happens when dstBuffer is not large enough to contain all decoded data.
* Remaining data will have to be presented again in a subsequent invocation.
*
* `dstBuffer` content is expected to be flushed between each invocation, as its content will be overwritten.
* `dstBuffer` can be changed at will between each consecutive function invocation.
*
* @return is an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call.
* Schematically, it's the size of the current (or remaining) compressed block + header of next block.
* Respecting the hint provides some boost to performance, since it does skip intermediate buffers.
* This is just a hint though, it's always possible to provide any srcSize.
* When a frame is fully decoded, @return will be 0 (no more data expected).
* If decompression failed, @return is an error code, which can be tested using LZ4F_isError().
*
* After a frame is fully decoded, dctx can be used again to decompress another frame.
*/
LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx,
void* dstBuffer, size_t* dstSizePtr,
const void* srcBuffer, size_t* srcSizePtr,
const LZ4F_decompressOptions_t* dOptPtr);
#if defined (__cplusplus)
}
#endif
#endif /* LZ4F_H_09782039843 */

View File

@ -0,0 +1,82 @@
/*
LZ4 auto-framing library
Header File for static linking only
Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 source repository : https://github.com/lz4/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
#ifndef LZ4FRAME_STATIC_H_0398209384
#define LZ4FRAME_STATIC_H_0398209384
#if defined (__cplusplus)
extern "C" {
#endif
/* lz4frame_static.h should be used solely in the context of static linking.
* It contains definitions which are not stable and may change in the future.
* Never use it in the context of DLL linking.
* */
/* --- Dependency --- */
#include "lz4frame.h"
/* --- Error List --- */
#define LZ4F_LIST_ERRORS(ITEM) \
ITEM(OK_NoError) ITEM(ERROR_GENERIC) \
ITEM(ERROR_maxBlockSize_invalid) ITEM(ERROR_blockMode_invalid) ITEM(ERROR_contentChecksumFlag_invalid) \
ITEM(ERROR_compressionLevel_invalid) \
ITEM(ERROR_headerVersion_wrong) ITEM(ERROR_blockChecksum_unsupported) ITEM(ERROR_reservedFlag_set) \
ITEM(ERROR_allocation_failed) \
ITEM(ERROR_srcSize_tooLarge) ITEM(ERROR_dstMaxSize_tooSmall) \
ITEM(ERROR_frameHeader_incomplete) ITEM(ERROR_frameType_unknown) ITEM(ERROR_frameSize_wrong) \
ITEM(ERROR_srcPtr_wrong) \
ITEM(ERROR_decompressionFailed) \
ITEM(ERROR_headerChecksum_invalid) ITEM(ERROR_contentChecksum_invalid) \
ITEM(ERROR_maxCode)
#define LZ4F_DISABLE_OLD_ENUMS /* comment to enable deprecated enums */
#ifndef LZ4F_DISABLE_OLD_ENUMS
# define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, ENUM = LZ4F_##ENUM,
#else
# define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,
#endif
typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes; /* enum is exposed, to handle specific errors; compare function result to -enum value */
LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult);
#if defined (__cplusplus)
}
#endif
#endif /* LZ4FRAME_STATIC_H_0398209384 */

View File

@ -0,0 +1,720 @@
/*
LZ4 HC - High Compression Mode of LZ4
Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 source repository : https://github.com/lz4/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
/* *************************************
* Tuning Parameter
***************************************/
/*!
* HEAPMODE :
* Select how default compression function will allocate workplace memory,
* in stack (0:fastest), or in heap (1:requires malloc()).
* Since workplace is rather large, heap mode is recommended.
*/
#ifndef LZ4HC_HEAPMODE
# define LZ4HC_HEAPMODE 1
#endif
/* *************************************
* Dependency
***************************************/
#include "lz4hc.h"
/* *************************************
* Local Compiler Options
***************************************/
#if defined(__GNUC__)
# pragma GCC diagnostic ignored "-Wunused-function"
#endif
#if defined (__clang__)
# pragma clang diagnostic ignored "-Wunused-function"
#endif
/* *************************************
* Common LZ4 definition
***************************************/
#define LZ4_COMMONDEFS_ONLY
#include "lz4.c"
/* *************************************
* Local Constants
***************************************/
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
/**************************************
* Local Macros
**************************************/
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
#define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
/**************************************
* HC Compression
**************************************/
static void LZ4HC_init (LZ4HC_CCtx_internal* hc4, const BYTE* start)
{
MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
hc4->nextToUpdate = 64 KB;
hc4->base = start - 64 KB;
hc4->end = start;
hc4->dictBase = start - 64 KB;
hc4->dictLimit = 64 KB;
hc4->lowLimit = 64 KB;
}
/* Update chains up to ip (excluded) */
FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
{
U16* const chainTable = hc4->chainTable;
U32* const hashTable = hc4->hashTable;
const BYTE* const base = hc4->base;
U32 const target = (U32)(ip - base);
U32 idx = hc4->nextToUpdate;
while (idx < target) {
U32 const h = LZ4HC_hashPtr(base+idx);
size_t delta = idx - hashTable[h];
if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
DELTANEXTU16(idx) = (U16)delta;
hashTable[h] = idx;
idx++;
}
hc4->nextToUpdate = target;
}
FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */
const BYTE* ip, const BYTE* const iLimit,
const BYTE** matchpos,
const int maxNbAttempts)
{
U16* const chainTable = hc4->chainTable;
U32* const HashTable = hc4->hashTable;
const BYTE* const base = hc4->base;
const BYTE* const dictBase = hc4->dictBase;
const U32 dictLimit = hc4->dictLimit;
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
U32 matchIndex;
int nbAttempts=maxNbAttempts;
size_t ml=0;
/* HC4 match finder */
LZ4HC_Insert(hc4, ip);
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
while ((matchIndex>=lowLimit) && (nbAttempts)) {
nbAttempts--;
if (matchIndex >= dictLimit) {
const BYTE* const match = base + matchIndex;
if (*(match+ml) == *(ip+ml)
&& (LZ4_read32(match) == LZ4_read32(ip)))
{
size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
if (mlt > ml) { ml = mlt; *matchpos = match; }
}
} else {
const BYTE* const match = dictBase + matchIndex;
if (LZ4_read32(match) == LZ4_read32(ip)) {
size_t mlt;
const BYTE* vLimit = ip + (dictLimit - matchIndex);
if (vLimit > iLimit) vLimit = iLimit;
mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
if ((ip+mlt == vLimit) && (vLimit < iLimit))
mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
}
}
matchIndex -= DELTANEXTU16(matchIndex);
}
return (int)ml;
}
FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
LZ4HC_CCtx_internal* hc4,
const BYTE* const ip,
const BYTE* const iLowLimit,
const BYTE* const iHighLimit,
int longest,
const BYTE** matchpos,
const BYTE** startpos,
const int maxNbAttempts)
{
U16* const chainTable = hc4->chainTable;
U32* const HashTable = hc4->hashTable;
const BYTE* const base = hc4->base;
const U32 dictLimit = hc4->dictLimit;
const BYTE* const lowPrefixPtr = base + dictLimit;
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
const BYTE* const dictBase = hc4->dictBase;
U32 matchIndex;
int nbAttempts = maxNbAttempts;
int delta = (int)(ip-iLowLimit);
/* First Match */
LZ4HC_Insert(hc4, ip);
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
while ((matchIndex>=lowLimit) && (nbAttempts)) {
nbAttempts--;
if (matchIndex >= dictLimit) {
const BYTE* matchPtr = base + matchIndex;
if (*(iLowLimit + longest) == *(matchPtr - delta + longest)) {
if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
int mlt = MINMATCH + LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);
int back = 0;
while ((ip+back > iLowLimit)
&& (matchPtr+back > lowPrefixPtr)
&& (ip[back-1] == matchPtr[back-1]))
back--;
mlt -= back;
if (mlt > longest) {
longest = (int)mlt;
*matchpos = matchPtr+back;
*startpos = ip+back;
}
}
}
} else {
const BYTE* const matchPtr = dictBase + matchIndex;
if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
size_t mlt;
int back=0;
const BYTE* vLimit = ip + (dictLimit - matchIndex);
if (vLimit > iHighLimit) vLimit = iHighLimit;
mlt = LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;
if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--;
mlt -= back;
if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
}
}
matchIndex -= DELTANEXTU16(matchIndex);
}
return longest;
}
typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
#define LZ4HC_DEBUG 0
#if LZ4HC_DEBUG
static unsigned debug = 0;
#endif
FORCE_INLINE int LZ4HC_encodeSequence (
const BYTE** ip,
BYTE** op,
const BYTE** anchor,
int matchLength,
const BYTE* const match,
limitedOutput_directive limitedOutputBuffer,
BYTE* oend)
{
int length;
BYTE* token;
#if LZ4HC_DEBUG
if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
#endif
/* Encode Literal length */
length = (int)(*ip - *anchor);
token = (*op)++;
if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
if (length>=(int)RUN_MASK) { int len; *token=(RUN_MASK<<ML_BITS); len = length-RUN_MASK; for(; len > 254 ; len-=255) *(*op)++ = 255; *(*op)++ = (BYTE)len; }
else *token = (BYTE)(length<<ML_BITS);
/* Copy Literals */
LZ4_wildCopy(*op, *anchor, (*op) + length);
*op += length;
/* Encode Offset */
LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
/* Encode MatchLength */
length = (int)(matchLength-MINMATCH);
if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
if (length>=(int)ML_MASK) {
*token += ML_MASK;
length -= ML_MASK;
for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; }
if (length > 254) { length-=255; *(*op)++ = 255; }
*(*op)++ = (BYTE)length;
} else {
*token += (BYTE)(length);
}
/* Prepare next loop */
*ip += matchLength;
*anchor = *ip;
return 0;
}
#include "lz4opt.h"
static int LZ4HC_compress_hashChain (
LZ4HC_CCtx_internal* const ctx,
const char* const source,
char* const dest,
int const inputSize,
int const maxOutputSize,
unsigned maxNbAttempts,
limitedOutput_directive limit
)
{
const BYTE* ip = (const BYTE*) source;
const BYTE* anchor = ip;
const BYTE* const iend = ip + inputSize;
const BYTE* const mflimit = iend - MFLIMIT;
const BYTE* const matchlimit = (iend - LASTLITERALS);
BYTE* op = (BYTE*) dest;
BYTE* const oend = op + maxOutputSize;
int ml, ml2, ml3, ml0;
const BYTE* ref = NULL;
const BYTE* start2 = NULL;
const BYTE* ref2 = NULL;
const BYTE* start3 = NULL;
const BYTE* ref3 = NULL;
const BYTE* start0;
const BYTE* ref0;
/* init */
ctx->end += inputSize;
ip++;
/* Main Loop */
while (ip < mflimit) {
ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
if (!ml) { ip++; continue; }
/* saved, in case we would skip too much */
start0 = ip;
ref0 = ref;
ml0 = ml;
_Search2:
if (ip+ml < mflimit)
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, maxNbAttempts);
else ml2 = ml;
if (ml2 == ml) { /* No better match */
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
continue;
}
if (start0 < ip) {
if (start2 < ip + ml0) { /* empirical */
ip = start0;
ref = ref0;
ml = ml0;
}
}
/* Here, start0==ip */
if ((start2 - ip) < 3) { /* First Match too small : removed */
ml = ml2;
ip = start2;
ref =ref2;
goto _Search2;
}
_Search3:
/*
* Currently we have :
* ml2 > ml1, and
* ip1+3 <= ip2 (usually < ip1+ml1)
*/
if ((start2 - ip) < OPTIMAL_ML) {
int correction;
int new_ml = ml;
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
correction = new_ml - (int)(start2 - ip);
if (correction > 0) {
start2 += correction;
ref2 += correction;
ml2 -= correction;
}
}
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
if (start2 + ml2 < mflimit)
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
else ml3 = ml2;
if (ml3 == ml2) { /* No better match : 2 sequences to encode */
/* ip & ref are known; Now for ml */
if (start2 < ip+ml) ml = (int)(start2 - ip);
/* Now, encode 2 sequences */
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
ip = start2;
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0;
continue;
}
if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */
if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
if (start2 < ip+ml) {
int correction = (int)(ip+ml - start2);
start2 += correction;
ref2 += correction;
ml2 -= correction;
if (ml2 < MINMATCH) {
start2 = start3;
ref2 = ref3;
ml2 = ml3;
}
}
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
ip = start3;
ref = ref3;
ml = ml3;
start0 = start2;
ref0 = ref2;
ml0 = ml2;
goto _Search2;
}
start2 = start3;
ref2 = ref3;
ml2 = ml3;
goto _Search3;
}
/*
* OK, now we have 3 ascending matches; let's write at least the first one
* ip & ref are known; Now for ml
*/
if (start2 < ip+ml) {
if ((start2 - ip) < (int)ML_MASK) {
int correction;
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
correction = ml - (int)(start2 - ip);
if (correction > 0) {
start2 += correction;
ref2 += correction;
ml2 -= correction;
}
} else {
ml = (int)(start2 - ip);
}
}
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
ip = start2;
ref = ref2;
ml = ml2;
start2 = start3;
ref2 = ref3;
ml2 = ml3;
goto _Search3;
}
/* Encode Last Literals */
{ int lastRun = (int)(iend - anchor);
if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */
if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
else *op++ = (BYTE)(lastRun<<ML_BITS);
memcpy(op, anchor, iend - anchor);
op += iend-anchor;
}
/* End */
return (int) (((char*)op)-dest);
}
static int LZ4HC_getSearchNum(int compressionLevel)
{
switch (compressionLevel) {
default: return 0; /* unused */
case 11: return 128;
case 12: return 1<<10;
}
}
static int LZ4HC_compress_generic (
LZ4HC_CCtx_internal* const ctx,
const char* const source,
char* const dest,
int const inputSize,
int const maxOutputSize,
int compressionLevel,
limitedOutput_directive limit
)
{
if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;
if (compressionLevel > 9) {
switch (compressionLevel) {
case 10: return LZ4HC_compress_hashChain(ctx, source, dest, inputSize, maxOutputSize, 1 << (16-1), limit);
case 11: ctx->searchNum = LZ4HC_getSearchNum(compressionLevel); return LZ4HC_compress_optimal(ctx, source, dest, inputSize, maxOutputSize, limit, 128, 0);
default:
case 12: ctx->searchNum = LZ4HC_getSearchNum(compressionLevel); return LZ4HC_compress_optimal(ctx, source, dest, inputSize, maxOutputSize, limit, LZ4_OPT_NUM, 1);
}
}
return LZ4HC_compress_hashChain(ctx, source, dest, inputSize, maxOutputSize, 1 << (compressionLevel-1), limit);
}
int LZ4_sizeofStateHC(void) { return sizeof(LZ4_streamHC_t); }
int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
{
LZ4HC_CCtx_internal* ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
LZ4HC_init (ctx, (const BYTE*)src);
if (maxDstSize < LZ4_compressBound(srcSize))
return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, limitedOutput);
else
return LZ4HC_compress_generic (ctx, src, dst, srcSize, maxDstSize, compressionLevel, noLimit);
}
int LZ4_compress_HC(const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel)
{
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t));
#else
LZ4_streamHC_t state;
LZ4_streamHC_t* const statePtr = &state;
#endif
int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, maxDstSize, compressionLevel);
#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1
free(statePtr);
#endif
return cSize;
}
/**************************************
* Streaming Functions
**************************************/
/* allocation */
LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; }
/* initialization */
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
{
LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= sizeof(size_t) * LZ4_STREAMHCSIZE_SIZET); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
LZ4_streamHCPtr->internal_donotuse.base = NULL;
LZ4_streamHCPtr->internal_donotuse.compressionLevel = (unsigned)compressionLevel;
LZ4_streamHCPtr->internal_donotuse.searchNum = LZ4HC_getSearchNum(compressionLevel);
}
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
{
LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
if (dictSize > 64 KB) {
dictionary += dictSize - 64 KB;
dictSize = 64 KB;
}
LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
ctxPtr->end = (const BYTE*)dictionary + dictSize;
if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS);
else
if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);
return dictSize;
}
/* compression */
static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)
{
if (ctxPtr->compressionLevel >= LZ4HC_CLEVEL_OPT_MIN)
LZ4HC_updateBinTree(ctxPtr, ctxPtr->end - MFLIMIT, ctxPtr->end - LASTLITERALS);
else
if (ctxPtr->end >= ctxPtr->base + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
ctxPtr->lowLimit = ctxPtr->dictLimit;
ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
ctxPtr->dictBase = ctxPtr->base;
ctxPtr->base = newBlock - ctxPtr->dictLimit;
ctxPtr->end = newBlock;
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
}
static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,
const char* source, char* dest,
int inputSize, int maxOutputSize, limitedOutput_directive limit)
{
LZ4HC_CCtx_internal* ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
/* auto-init if forgotten */
if (ctxPtr->base == NULL) LZ4HC_init (ctxPtr, (const BYTE*) source);
/* Check overflow */
if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
if (dictSize > 64 KB) dictSize = 64 KB;
LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
}
/* Check if blocks follow each other */
if ((const BYTE*)source != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source);
/* Check overlapping input/dictionary space */
{ const BYTE* sourceEnd = (const BYTE*) source + inputSize;
const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
if ((sourceEnd > dictBegin) && ((const BYTE*)source < dictEnd)) {
if (sourceEnd > dictEnd) sourceEnd = dictEnd;
ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
}
}
return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
}
int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize)
{
if (maxOutputSize < LZ4_compressBound(inputSize))
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput);
else
return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, noLimit);
}
/* dictionary saving */
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
{
LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;
int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
if (dictSize > 64 KB) dictSize = 64 KB;
if (dictSize < 4) dictSize = 0;
if (dictSize > prefixSize) dictSize = prefixSize;
memmove(safeBuffer, streamPtr->end - dictSize, dictSize);
{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
streamPtr->base = streamPtr->end - endIndex;
streamPtr->dictLimit = endIndex - dictSize;
streamPtr->lowLimit = endIndex - dictSize;
if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
}
return dictSize;
}
/***********************************
* Deprecated Functions
***********************************/
/* These functions currently generate deprecation warnings */
/* Deprecated compression functions */
int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }
int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }
int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }
int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }
int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }
int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }
/* Deprecated streaming functions */
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
int LZ4_resetStreamStateHC(void* state, char* inputBuffer)
{
LZ4HC_CCtx_internal *ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;
if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */
LZ4HC_init(ctx, (const BYTE*)inputBuffer);
ctx->inputBuffer = (BYTE*)inputBuffer;
return 0;
}
void* LZ4_createHC (char* inputBuffer)
{
LZ4_streamHC_t* hc4 = (LZ4_streamHC_t*)ALLOCATOR(1, sizeof(LZ4_streamHC_t));
if (hc4 == NULL) return NULL; /* not enough memory */
LZ4HC_init (&hc4->internal_donotuse, (const BYTE*)inputBuffer);
hc4->internal_donotuse.inputBuffer = (BYTE*)inputBuffer;
return hc4;
}
int LZ4_freeHC (void* LZ4HC_Data) { FREEMEM(LZ4HC_Data); return 0; }
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel)
{
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, 0, compressionLevel, noLimit);
}
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
{
return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
}
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
{
LZ4HC_CCtx_internal* const hc4 = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;
int const dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
return (char*)(hc4->inputBuffer + dictSize);
}

View File

@ -0,0 +1,228 @@
/*
LZ4 HC - High Compression Mode of LZ4
Header File
Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 source repository : https://github.com/lz4/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
#ifndef LZ4_HC_H_19834876238432
#define LZ4_HC_H_19834876238432
#if defined (__cplusplus)
extern "C" {
#endif
/* --- Dependency --- */
/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
#include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */
/* --- Useful constants --- */
#define LZ4HC_CLEVEL_MIN 3
#define LZ4HC_CLEVEL_DEFAULT 9
#define LZ4HC_CLEVEL_OPT_MIN 11
#define LZ4HC_CLEVEL_MAX 12
/*-************************************
* Block Compression
**************************************/
/*! LZ4_compress_HC() :
* Compress data from `src` into `dst`, using the more powerful but slower "HC" algorithm.
* `dst` must be already allocated.
* Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see "lz4.h")
* Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see "lz4.h")
* `compressionLevel` : Recommended values are between 4 and 9, although any value between 1 and LZ4HC_MAX_CLEVEL will work.
* Values >LZ4HC_MAX_CLEVEL behave the same as LZ4HC_MAX_CLEVEL.
* @return : the number of bytes written into 'dst'
* or 0 if compression fails.
*/
LZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);
/* Note :
* Decompression functions are provided within "lz4.h" (BSD license)
*/
/*! LZ4_compress_HC_extStateHC() :
* Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`.
* `state` size is provided by LZ4_sizeofStateHC().
* Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() will do properly).
*/
LZ4LIB_API int LZ4_compress_HC_extStateHC(void* state, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);
LZ4LIB_API int LZ4_sizeofStateHC(void);
/*-************************************
* Streaming Compression
* Bufferless synchronous API
**************************************/
typedef union LZ4_streamHC_u LZ4_streamHC_t; /* incomplete type (defined later) */
/*! LZ4_createStreamHC() and LZ4_freeStreamHC() :
* These functions create and release memory for LZ4 HC streaming state.
* Newly created states are automatically initialized.
* Existing states can be re-used several times, using LZ4_resetStreamHC().
* These methods are API and ABI stable, they can be used in combination with a DLL.
*/
LZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void);
LZ4LIB_API int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr);
LZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel);
LZ4LIB_API int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize);
LZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize);
LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);
/*
These functions compress data in successive blocks of any size, using previous blocks as dictionary.
One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks.
There is an exception for ring buffers, which can be smaller than 64 KB.
Ring buffers scenario is automatically detected and handled by LZ4_compress_HC_continue().
Before starting compression, state must be properly initialized, using LZ4_resetStreamHC().
A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional).
Then, use LZ4_compress_HC_continue() to compress each successive block.
Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression.
'dst' buffer should be sized to handle worst case scenarios, using LZ4_compressBound(), to ensure operation success.
If, for any reason, previous data blocks can't be preserved unmodified in memory during next compression block,
you must save it to a safer memory space, using LZ4_saveDictHC().
Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer'.
*/
/*-******************************************
* !!!!! STATIC LINKING ONLY !!!!!
*******************************************/
/*-*************************************
* PRIVATE DEFINITIONS :
* Do not use these definitions.
* They are exposed to allow static allocation of `LZ4_streamHC_t`.
* Using these definitions makes the code vulnerable to potential API break when upgrading LZ4
**************************************/
#define LZ4HC_DICTIONARY_LOGSIZE 17
#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)
#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)
#define LZ4HC_HASH_LOG 15
#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)
#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
#include <stdint.h>
typedef struct
{
uint32_t hashTable[LZ4HC_HASHTABLESIZE];
uint16_t chainTable[LZ4HC_MAXD];
const uint8_t* end; /* next block here to continue on current prefix */
const uint8_t* base; /* All index relative to this position */
const uint8_t* dictBase; /* alternate base for extDict */
uint8_t* inputBuffer; /* deprecated */
uint32_t dictLimit; /* below that point, need extDict */
uint32_t lowLimit; /* below that point, no more dict */
uint32_t nextToUpdate; /* index from which to continue dictionary update */
uint32_t searchNum; /* only for optimal parser */
uint32_t compressionLevel;
} LZ4HC_CCtx_internal;
#else
typedef struct
{
unsigned int hashTable[LZ4HC_HASHTABLESIZE];
unsigned short chainTable[LZ4HC_MAXD];
const unsigned char* end; /* next block here to continue on current prefix */
const unsigned char* base; /* All index relative to this position */
const unsigned char* dictBase; /* alternate base for extDict */
unsigned char* inputBuffer; /* deprecated */
unsigned int dictLimit; /* below that point, need extDict */
unsigned int lowLimit; /* below that point, no more dict */
unsigned int nextToUpdate; /* index from which to continue dictionary update */
unsigned int searchNum; /* only for optimal parser */
unsigned int compressionLevel;
} LZ4HC_CCtx_internal;
#endif
#define LZ4_STREAMHCSIZE (4*LZ4HC_HASHTABLESIZE + 2*LZ4HC_MAXD + 56) /* 393268 */
#define LZ4_STREAMHCSIZE_SIZET (LZ4_STREAMHCSIZE / sizeof(size_t))
union LZ4_streamHC_u {
size_t table[LZ4_STREAMHCSIZE_SIZET];
LZ4HC_CCtx_internal internal_donotuse;
}; /* previously typedef'd to LZ4_streamHC_t */
/*
LZ4_streamHC_t :
This structure allows static allocation of LZ4 HC streaming state.
State must be initialized using LZ4_resetStreamHC() before first use.
Static allocation shall only be used in combination with static linking.
When invoking LZ4 from a DLL, use create/free functions instead, which are API and ABI stable.
*/
/*-************************************
* Deprecated Functions
**************************************/
/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */
/* deprecated compression functions */
/* these functions will trigger warning messages in future releases */
LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC (const char* source, char* dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC() instead") int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC_extStateHC() instead") int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
/* Deprecated Streaming functions using older model; should no longer be used */
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") void* LZ4_createHC (char* inputBuffer);
LZ4_DEPRECATED("use LZ4_saveDictHC() instead") char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
LZ4_DEPRECATED("use LZ4_freeStreamHC() instead") int LZ4_freeHC (void* LZ4HC_Data);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_compress_HC_continue() instead") int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
LZ4_DEPRECATED("use LZ4_createStreamHC() instead") int LZ4_sizeofStreamStateHC(void);
LZ4_DEPRECATED("use LZ4_resetStreamHC() instead") int LZ4_resetStreamStateHC(void* state, char* inputBuffer);
#if defined (__cplusplus)
}
#endif
#endif /* LZ4_HC_H_19834876238432 */

View File

@ -0,0 +1,363 @@
/*
lz4opt.h - Optimal Mode of LZ4
Copyright (C) 2015-2016, Przemyslaw Skibinski <inikep@gmail.com>
Note : this file is intended to be included within lz4hc.c
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 source repository : https://github.com/lz4/lz4
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
*/
#define LZ4_OPT_NUM (1<<12)
typedef struct
{
int off;
int len;
} LZ4HC_match_t;
typedef struct
{
int price;
int off;
int mlen;
int litlen;
} LZ4HC_optimal_t;
/* price in bits */
FORCE_INLINE size_t LZ4HC_literalsPrice(size_t litlen)
{
size_t price = 8*litlen;
if (litlen >= (size_t)RUN_MASK) price+=8*(1+(litlen-RUN_MASK)/255);
return price;
}
/* requires mlen >= MINMATCH */
FORCE_INLINE size_t LZ4HC_sequencePrice(size_t litlen, size_t mlen)
{
size_t price = 16 + 8; /* 16-bit offset + token */
price += LZ4HC_literalsPrice(litlen);
mlen -= MINMATCH;
if (mlen >= (size_t)ML_MASK) price+=8*(1+(mlen-ML_MASK)/255);
return price;
}
/*-*************************************
* Binary Tree search
***************************************/
FORCE_INLINE int LZ4HC_BinTree_InsertAndGetAllMatches (
LZ4HC_CCtx_internal* ctx,
const BYTE* const ip,
const BYTE* const iHighLimit,
size_t best_mlen,
LZ4HC_match_t* matches,
int* matchNum)
{
U16* const chainTable = ctx->chainTable;
U32* const HashTable = ctx->hashTable;
const BYTE* const base = ctx->base;
const U32 dictLimit = ctx->dictLimit;
const U32 current = (U32)(ip - base);
const U32 lowLimit = (ctx->lowLimit + MAX_DISTANCE > current) ? ctx->lowLimit : current - (MAX_DISTANCE - 1);
const BYTE* const dictBase = ctx->dictBase;
const BYTE* match;
int nbAttempts = ctx->searchNum;
int mnum = 0;
U16 *ptr0, *ptr1, delta0, delta1;
U32 matchIndex;
size_t matchLength = 0;
U32* HashPos;
if (ip + MINMATCH > iHighLimit) return 1;
/* HC4 match finder */
HashPos = &HashTable[LZ4HC_hashPtr(ip)];
matchIndex = *HashPos;
*HashPos = current;
ptr0 = &DELTANEXTMAXD(current*2+1);
ptr1 = &DELTANEXTMAXD(current*2);
delta0 = delta1 = (U16)(current - matchIndex);
while ((matchIndex < current) && (matchIndex>=lowLimit) && (nbAttempts)) {
nbAttempts--;
if (matchIndex >= dictLimit) {
match = base + matchIndex;
matchLength = LZ4_count(ip, match, iHighLimit);
} else {
const BYTE* vLimit = ip + (dictLimit - matchIndex);
match = dictBase + matchIndex;
if (vLimit > iHighLimit) vLimit = iHighLimit;
matchLength = LZ4_count(ip, match, vLimit);
if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))
matchLength += LZ4_count(ip+matchLength, base+dictLimit, iHighLimit);
}
if (matchLength > best_mlen) {
best_mlen = matchLength;
if (matches) {
if (matchIndex >= dictLimit)
matches[mnum].off = (int)(ip - match);
else
matches[mnum].off = (int)(ip - (base + matchIndex)); /* virtual matchpos */
matches[mnum].len = (int)matchLength;
mnum++;
}
if (best_mlen > LZ4_OPT_NUM) break;
}
if (ip+matchLength >= iHighLimit) /* equal : no way to know if inf or sup */
break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
if (*(ip+matchLength) < *(match+matchLength)) {
*ptr0 = delta0;
ptr0 = &DELTANEXTMAXD(matchIndex*2);
if (*ptr0 == (U16)-1) break;
delta0 = *ptr0;
delta1 += delta0;
matchIndex -= delta0;
} else {
*ptr1 = delta1;
ptr1 = &DELTANEXTMAXD(matchIndex*2+1);
if (*ptr1 == (U16)-1) break;
delta1 = *ptr1;
delta0 += delta1;
matchIndex -= delta1;
}
}
*ptr0 = (U16)-1;
*ptr1 = (U16)-1;
if (matchNum) *matchNum = mnum;
/* if (best_mlen > 8) return best_mlen-8; */
if (!matchNum) return 1;
return 1;
}
FORCE_INLINE void LZ4HC_updateBinTree(LZ4HC_CCtx_internal* ctx, const BYTE* const ip, const BYTE* const iHighLimit)
{
const BYTE* const base = ctx->base;
const U32 target = (U32)(ip - base);
U32 idx = ctx->nextToUpdate;
while(idx < target)
idx += LZ4HC_BinTree_InsertAndGetAllMatches(ctx, base+idx, iHighLimit, 8, NULL, NULL);
}
/** Tree updater, providing best match */
FORCE_INLINE int LZ4HC_BinTree_GetAllMatches (
LZ4HC_CCtx_internal* ctx,
const BYTE* const ip, const BYTE* const iHighLimit,
size_t best_mlen, LZ4HC_match_t* matches, const int fullUpdate)
{
int mnum = 0;
if (ip < ctx->base + ctx->nextToUpdate) return 0; /* skipped area */
if (fullUpdate) LZ4HC_updateBinTree(ctx, ip, iHighLimit);
best_mlen = LZ4HC_BinTree_InsertAndGetAllMatches(ctx, ip, iHighLimit, best_mlen, matches, &mnum);
ctx->nextToUpdate = (U32)(ip - ctx->base + best_mlen);
return mnum;
}
#define SET_PRICE(pos, mlen, offset, litlen, price) \
{ \
while (last_pos < pos) { opt[last_pos+1].price = 1<<30; last_pos++; } \
opt[pos].mlen = (int)mlen; \
opt[pos].off = (int)offset; \
opt[pos].litlen = (int)litlen; \
opt[pos].price = (int)price; \
}
static int LZ4HC_compress_optimal (
LZ4HC_CCtx_internal* ctx,
const char* const source,
char* dest,
int inputSize,
int maxOutputSize,
limitedOutput_directive limit,
const size_t sufficient_len,
const int fullUpdate
)
{
LZ4HC_optimal_t opt[LZ4_OPT_NUM + 1];
LZ4HC_match_t matches[LZ4_OPT_NUM + 1];
const BYTE *inr = NULL;
size_t res, cur, cur2;
size_t i, llen, litlen, mlen, best_mlen, price, offset, best_off, match_num, last_pos;
const BYTE* ip = (const BYTE*) source;
const BYTE* anchor = ip;
const BYTE* const iend = ip + inputSize;
const BYTE* const mflimit = iend - MFLIMIT;
const BYTE* const matchlimit = (iend - LASTLITERALS);
BYTE* op = (BYTE*) dest;
BYTE* const oend = op + maxOutputSize;
/* init */
ctx->end += inputSize;
ip++;
/* Main Loop */
while (ip < mflimit) {
memset(opt, 0, sizeof(LZ4HC_optimal_t));
last_pos = 0;
llen = ip - anchor;
match_num = LZ4HC_BinTree_GetAllMatches(ctx, ip, matchlimit, MINMATCH-1, matches, fullUpdate);
if (!match_num) { ip++; continue; }
if ((size_t)matches[match_num-1].len > sufficient_len) {
best_mlen = matches[match_num-1].len;
best_off = matches[match_num-1].off;
cur = 0;
last_pos = 1;
goto encode;
}
/* set prices using matches at position = 0 */
for (i = 0; i < match_num; i++) {
mlen = (i>0) ? (size_t)matches[i-1].len+1 : MINMATCH;
best_mlen = (matches[i].len < LZ4_OPT_NUM) ? matches[i].len : LZ4_OPT_NUM;
while (mlen <= best_mlen) {
litlen = 0;
price = LZ4HC_sequencePrice(llen + litlen, mlen) - LZ4HC_literalsPrice(llen);
SET_PRICE(mlen, mlen, matches[i].off, litlen, price);
mlen++;
}
}
if (last_pos < MINMATCH) { ip++; continue; }
/* check further positions */
opt[0].mlen = opt[1].mlen = 1;
for (cur = 1; cur <= last_pos; cur++) {
inr = ip + cur;
if (opt[cur-1].mlen == 1) {
litlen = opt[cur-1].litlen + 1;
if (cur != litlen) {
price = opt[cur - litlen].price + LZ4HC_literalsPrice(litlen);
} else {
price = LZ4HC_literalsPrice(llen + litlen) - LZ4HC_literalsPrice(llen);
}
} else {
litlen = 1;
price = opt[cur - 1].price + LZ4HC_literalsPrice(litlen);
}
mlen = 1;
best_mlen = 0;
if (cur > last_pos || price < (size_t)opt[cur].price)
SET_PRICE(cur, mlen, best_mlen, litlen, price);
if (cur == last_pos || inr >= mflimit) break;
match_num = LZ4HC_BinTree_GetAllMatches(ctx, inr, matchlimit, MINMATCH-1, matches, fullUpdate);
if (match_num > 0 && (size_t)matches[match_num-1].len > sufficient_len) {
best_mlen = matches[match_num-1].len;
best_off = matches[match_num-1].off;
last_pos = cur + 1;
goto encode;
}
/* set prices using matches at position = cur */
for (i = 0; i < match_num; i++) {
mlen = (i>0) ? (size_t)matches[i-1].len+1 : MINMATCH;
cur2 = cur;
best_mlen = (cur2 + matches[i].len < LZ4_OPT_NUM) ? (size_t)matches[i].len : LZ4_OPT_NUM - cur2;
while (mlen <= best_mlen) {
if (opt[cur2].mlen == 1) {
litlen = opt[cur2].litlen;
if (cur2 != litlen)
price = opt[cur2 - litlen].price + LZ4HC_sequencePrice(litlen, mlen);
else
price = LZ4HC_sequencePrice(llen + litlen, mlen) - LZ4HC_literalsPrice(llen);
} else {
litlen = 0;
price = opt[cur2].price + LZ4HC_sequencePrice(litlen, mlen);
}
if (cur2 + mlen > last_pos || price < (size_t)opt[cur2 + mlen].price) { // || (((int)price == opt[cur2 + mlen].price) && (opt[cur2 + mlen-1].mlen == 1))) {
SET_PRICE(cur2 + mlen, mlen, matches[i].off, litlen, price);
}
mlen++;
}
}
} /* for (cur = 1; cur <= last_pos; cur++) */
best_mlen = opt[last_pos].mlen;
best_off = opt[last_pos].off;
cur = last_pos - best_mlen;
encode: /* cur, last_pos, best_mlen, best_off have to be set */
opt[0].mlen = 1;
while (1) {
mlen = opt[cur].mlen;
offset = opt[cur].off;
opt[cur].mlen = (int)best_mlen;
opt[cur].off = (int)best_off;
best_mlen = mlen;
best_off = offset;
if (mlen > cur) break;
cur -= mlen;
}
cur = 0;
while (cur < last_pos) {
mlen = opt[cur].mlen;
if (mlen == 1) { ip++; cur++; continue; }
offset = opt[cur].off;
cur += mlen;
res = LZ4HC_encodeSequence(&ip, &op, &anchor, (int)mlen, ip - offset, limit, oend);
if (res) return 0;
}
}
/* Encode Last Literals */
{ int lastRun = (int)(iend - anchor);
if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */
if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
else *op++ = (BYTE)(lastRun<<ML_BITS);
memcpy(op, anchor, iend - anchor);
op += iend-anchor;
}
/* End */
return (int) ((char*)op-dest);
}

View File

@ -0,0 +1,889 @@
/*
* xxHash - Fast Hash algorithm
* Copyright (C) 2012-2016, Yann Collet
*
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at :
* - xxHash homepage: http://www.xxhash.com
* - xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* *************************************
* Tuning parameters
***************************************/
/*!XXH_FORCE_MEMORY_ACCESS :
* By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
* Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
* The below switch allow to select different access method for improved performance.
* Method 0 (default) : use `memcpy()`. Safe and portable.
* Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
* This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
* Method 2 : direct access. This method doesn't depend on compiler but violate C standard.
* It can generate buggy code on targets which do not support unaligned memory accesses.
* But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
* See http://stackoverflow.com/a/32095106/646947 for details.
* Prefer these methods in priority order (0 > 1 > 2)
*/
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
# if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
# define XXH_FORCE_MEMORY_ACCESS 2
# elif defined(__INTEL_COMPILER) || \
(defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
# define XXH_FORCE_MEMORY_ACCESS 1
# endif
#endif
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
* By default, this option is disabled. To enable it, uncomment below define :
*/
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
/*!XXH_FORCE_NATIVE_FORMAT :
* By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
* Results are therefore identical for little-endian and big-endian CPU.
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
* Should endian-independence be of no importance for your application, you may set the #define below to 1,
* to improve speed for Big-endian CPU.
* This option has no impact on Little_Endian CPU.
*/
#ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */
# define XXH_FORCE_NATIVE_FORMAT 0
#endif
/*!XXH_FORCE_ALIGN_CHECK :
* This is a minor performance trick, only useful with lots of very small keys.
* It means : check for aligned/unaligned input.
* The check costs one initial branch per hash; set to 0 when the input data
* is guaranteed to be aligned.
*/
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
# if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
# define XXH_FORCE_ALIGN_CHECK 0
# else
# define XXH_FORCE_ALIGN_CHECK 1
# endif
#endif
/* *************************************
* Includes & Memory related functions
***************************************/
/*! Modify the local functions below should you wish to use some other memory routines
* for malloc(), free() */
#include <stdlib.h>
static void* XXH_malloc(size_t s) { return malloc(s); }
static void XXH_free (void* p) { free(p); }
/*! and for memcpy() */
#include <string.h>
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
#define XXH_STATIC_LINKING_ONLY
#include "xxhash.h"
/* *************************************
* Compiler Specific Options
***************************************/
#ifdef _MSC_VER /* Visual Studio */
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
# define FORCE_INLINE static __forceinline
#else
# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
# ifdef __GNUC__
# define FORCE_INLINE static inline __attribute__((always_inline))
# else
# define FORCE_INLINE static inline
# endif
# else
# define FORCE_INLINE static
# endif /* __STDC_VERSION__ */
#endif
/* *************************************
* Basic Types
***************************************/
#ifndef MEM_MODULE
# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint8_t BYTE;
typedef uint16_t U16;
typedef uint32_t U32;
typedef int32_t S32;
# else
typedef unsigned char BYTE;
typedef unsigned short U16;
typedef unsigned int U32;
typedef signed int S32;
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; } __attribute__((packed)) unalign;
static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U32 XXH_read32(const void* memPtr)
{
U32 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
/* ****************************************
* Compiler-specific Functions and Macros
******************************************/
#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
#if defined(_MSC_VER)
# define XXH_rotl32(x,r) _rotl(x,r)
# define XXH_rotl64(x,r) _rotl64(x,r)
#else
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
#endif
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap32 _byteswap_ulong
#elif XXH_GCC_VERSION >= 403
# define XXH_swap32 __builtin_bswap32
#else
static U32 XXH_swap32 (U32 x)
{
return ((x << 24) & 0xff000000 ) |
((x << 8) & 0x00ff0000 ) |
((x >> 8) & 0x0000ff00 ) |
((x >> 24) & 0x000000ff );
}
#endif
/* *************************************
* Architecture Macros
***************************************/
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
#ifndef XXH_CPU_LITTLE_ENDIAN
static const int g_one = 1;
# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&g_one))
#endif
/* ***************************
* Memory reads
*****************************/
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
else
return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
}
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
{
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
}
static U32 XXH_readBE32(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);
}
/* *************************************
* Macros
***************************************/
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
/* *******************************************************************
* 32-bits hash functions
*********************************************************************/
static const U32 PRIME32_1 = 2654435761U;
static const U32 PRIME32_2 = 2246822519U;
static const U32 PRIME32_3 = 3266489917U;
static const U32 PRIME32_4 = 668265263U;
static const U32 PRIME32_5 = 374761393U;
static U32 XXH32_round(U32 seed, U32 input)
{
seed += input * PRIME32_2;
seed = XXH_rotl32(seed, 13);
seed *= PRIME32_1;
return seed;
}
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* bEnd = p + len;
U32 h32;
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)16;
}
#endif
if (len>=16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = seed + PRIME32_1 + PRIME32_2;
U32 v2 = seed + PRIME32_2;
U32 v3 = seed + 0;
U32 v4 = seed - PRIME32_1;
do {
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
} while (p<=limit);
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
} else {
h32 = seed + PRIME32_5;
}
h32 += (U32) len;
while (p+4<=bEnd) {
h32 += XXH_get32bits(p) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH32_state_t state;
XXH32_reset(&state, seed);
XXH32_update(&state, input, len);
return XXH32_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash streaming ======*/
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
{
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
{
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
state.v1 = seed + PRIME32_1 + PRIME32_2;
state.v2 = seed + PRIME32_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME32_1;
memcpy(statePtr, &state, sizeof(state));
return XXH_OK;
}
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
if (input==NULL) return XXH_ERROR;
#endif
state->total_len_32 += (unsigned)len;
state->large_len |= (len>=16) | (state->total_len_32>=16);
if (state->memsize + len < 16) { /* fill in tmp buffer */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
state->memsize += (unsigned)len;
return XXH_OK;
}
if (state->memsize) { /* some data left from previous update */
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
{ const U32* p32 = state->mem32;
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
}
p += 16-state->memsize;
state->memsize = 0;
}
if (p <= bEnd-16) {
const BYTE* const limit = bEnd - 16;
U32 v1 = state->v1;
U32 v2 = state->v2;
U32 v3 = state->v3;
U32 v4 = state->v4;
do {
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem32;
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
U32 h32;
if (state->large_len) {
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
} else {
h32 = state->v3 /* == seed */ + PRIME32_5;
}
h32 += state->total_len_32;
while (p+4<=bEnd) {
h32 += XXH_readLE32(p, endian) * PRIME32_3;
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
p+=4;
}
while (p<bEnd) {
h32 += (*p) * PRIME32_5;
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
p++;
}
h32 ^= h32 >> 15;
h32 *= PRIME32_2;
h32 ^= h32 >> 13;
h32 *= PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH32_digest_endian(state_in, XXH_littleEndian);
else
return XXH32_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
/*! Default XXH result types are basic unsigned 32 and 64 bits.
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
*/
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
{
return XXH_readBE32(src);
}
#ifndef XXH_NO_LONG_LONG
/* *******************************************************************
* 64-bits hash functions
*********************************************************************/
/*====== Memory access ======*/
#ifndef MEM_MODULE
# define MEM_MODULE
# if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
# include <stdint.h>
typedef uint64_t U64;
# else
typedef unsigned long long U64; /* if your compiler doesn't support unsigned long long, replace by another 64-bit type here. Note that xxhash.h will also need to be updated. */
# endif
#endif
#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))
/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */
static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
/* currently only defined for gcc and icc */
typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;
static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }
#else
/* portable and safe solution. Generally efficient.
* see : http://stackoverflow.com/a/32095106/646947
*/
static U64 XXH_read64(const void* memPtr)
{
U64 val;
memcpy(&val, memPtr, sizeof(val));
return val;
}
#endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */
#if defined(_MSC_VER) /* Visual Studio */
# define XXH_swap64 _byteswap_uint64
#elif XXH_GCC_VERSION >= 403
# define XXH_swap64 __builtin_bswap64
#else
static U64 XXH_swap64 (U64 x)
{
return ((x << 56) & 0xff00000000000000ULL) |
((x << 40) & 0x00ff000000000000ULL) |
((x << 24) & 0x0000ff0000000000ULL) |
((x << 8) & 0x000000ff00000000ULL) |
((x >> 8) & 0x00000000ff000000ULL) |
((x >> 24) & 0x0000000000ff0000ULL) |
((x >> 40) & 0x000000000000ff00ULL) |
((x >> 56) & 0x00000000000000ffULL);
}
#endif
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
{
if (align==XXH_unaligned)
return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
else
return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
}
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
{
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
}
static U64 XXH_readBE64(const void* ptr)
{
return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);
}
/*====== xxh64 ======*/
static const U64 PRIME64_1 = 11400714785074694791ULL;
static const U64 PRIME64_2 = 14029467366897019727ULL;
static const U64 PRIME64_3 = 1609587929392839161ULL;
static const U64 PRIME64_4 = 9650029242287828579ULL;
static const U64 PRIME64_5 = 2870177450012600261ULL;
static U64 XXH64_round(U64 acc, U64 input)
{
acc += input * PRIME64_2;
acc = XXH_rotl64(acc, 31);
acc *= PRIME64_1;
return acc;
}
static U64 XXH64_mergeRound(U64 acc, U64 val)
{
val = XXH64_round(0, val);
acc ^= val;
acc = acc * PRIME64_1 + PRIME64_4;
return acc;
}
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
U64 h64;
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
if (p==NULL) {
len=0;
bEnd=p=(const BYTE*)(size_t)32;
}
#endif
if (len>=32) {
const BYTE* const limit = bEnd - 32;
U64 v1 = seed + PRIME64_1 + PRIME64_2;
U64 v2 = seed + PRIME64_2;
U64 v3 = seed + 0;
U64 v4 = seed - PRIME64_1;
do {
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
} while (p<=limit);
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = seed + PRIME64_5;
}
h64 += (U64) len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
{
#if 0
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
XXH64_state_t state;
XXH64_reset(&state, seed);
XXH64_update(&state, input, len);
return XXH64_digest(&state);
#else
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if (XXH_FORCE_ALIGN_CHECK) {
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
} }
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
else
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
#endif
}
/*====== Hash Streaming ======*/
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
{
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
}
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
{
XXH_free(statePtr);
return XXH_OK;
}
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
{
memcpy(dstState, srcState, sizeof(*dstState));
}
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
{
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
state.v1 = seed + PRIME64_1 + PRIME64_2;
state.v2 = seed + PRIME64_2;
state.v3 = seed + 0;
state.v4 = seed - PRIME64_1;
memcpy(statePtr, &state, sizeof(state));
return XXH_OK;
}
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
{
const BYTE* p = (const BYTE*)input;
const BYTE* const bEnd = p + len;
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
if (input==NULL) return XXH_ERROR;
#endif
state->total_len += len;
if (state->memsize + len < 32) { /* fill in tmp buffer */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
state->memsize += (U32)len;
return XXH_OK;
}
if (state->memsize) { /* tmp buffer is full */
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
p += 32-state->memsize;
state->memsize = 0;
}
if (p+32 <= bEnd) {
const BYTE* const limit = bEnd - 32;
U64 v1 = state->v1;
U64 v2 = state->v2;
U64 v3 = state->v3;
U64 v4 = state->v4;
do {
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
} while (p<=limit);
state->v1 = v1;
state->v2 = v2;
state->v3 = v3;
state->v4 = v4;
}
if (p < bEnd) {
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
state->memsize = (unsigned)(bEnd-p);
}
return XXH_OK;
}
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
else
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
}
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
{
const BYTE * p = (const BYTE*)state->mem64;
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
U64 h64;
if (state->total_len >= 32) {
U64 const v1 = state->v1;
U64 const v2 = state->v2;
U64 const v3 = state->v3;
U64 const v4 = state->v4;
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
h64 = XXH64_mergeRound(h64, v1);
h64 = XXH64_mergeRound(h64, v2);
h64 = XXH64_mergeRound(h64, v3);
h64 = XXH64_mergeRound(h64, v4);
} else {
h64 = state->v3 + PRIME64_5;
}
h64 += (U64) state->total_len;
while (p+8<=bEnd) {
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
p+=8;
}
if (p+4<=bEnd) {
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
p+=4;
}
while (p<bEnd) {
h64 ^= (*p) * PRIME64_5;
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
p++;
}
h64 ^= h64 >> 33;
h64 *= PRIME64_2;
h64 ^= h64 >> 29;
h64 *= PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
{
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
return XXH64_digest_endian(state_in, XXH_littleEndian);
else
return XXH64_digest_endian(state_in, XXH_bigEndian);
}
/*====== Canonical representation ======*/
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
{
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
memcpy(dst, &hash, sizeof(*dst));
}
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
{
return XXH_readBE64(src);
}
#endif /* XXH_NO_LONG_LONG */

View File

@ -0,0 +1,293 @@
/*
xxHash - Extremely Fast Hash algorithm
Header File
Copyright (C) 2012-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- xxHash source repository : https://github.com/Cyan4973/xxHash
*/
/* Notice extracted from xxHash homepage :
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
It also successfully passes all tests from the SMHasher suite.
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
Name Speed Q.Score Author
xxHash 5.4 GB/s 10
CrapWow 3.2 GB/s 2 Andrew
MumurHash 3a 2.7 GB/s 10 Austin Appleby
SpookyHash 2.0 GB/s 10 Bob Jenkins
SBox 1.4 GB/s 9 Bret Mulvey
Lookup3 1.2 GB/s 9 Bob Jenkins
SuperFastHash 1.2 GB/s 1 Paul Hsieh
CityHash64 1.05 GB/s 10 Pike & Alakuijala
FNV 0.55 GB/s 5 Fowler, Noll, Vo
CRC32 0.43 GB/s 9
MD5-32 0.33 GB/s 10 Ronald L. Rivest
SHA1-32 0.28 GB/s 10
Q.Score is a measure of quality of the hash function.
It depends on successfully passing SMHasher test set.
10 is a perfect score.
A 64-bits version, named XXH64, is available since r35.
It offers much better speed, but for 64-bits applications only.
Name Speed on 64 bits Speed on 32 bits
XXH64 13.8 GB/s 1.9 GB/s
XXH32 6.8 GB/s 6.0 GB/s
*/
#ifndef XXHASH_H_5627135585666179
#define XXHASH_H_5627135585666179 1
#if defined (__cplusplus)
extern "C" {
#endif
/* ****************************
* Definitions
******************************/
#include <stddef.h> /* size_t */
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
/* ****************************
* API modifier
******************************/
/** XXH_PRIVATE_API
* This is useful to include xxhash functions in `static` mode
* in order to inline them, and remove their symbol from the public list.
* Methodology :
* #define XXH_PRIVATE_API
* #include "xxhash.h"
* `xxhash.c` is automatically included.
* It's not useful to compile and link it as a separate module.
*/
#ifdef XXH_PRIVATE_API
# ifndef XXH_STATIC_LINKING_ONLY
# define XXH_STATIC_LINKING_ONLY
# endif
# if defined(__GNUC__)
# define XXH_PUBLIC_API static __inline __attribute__((unused))
# elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# define XXH_PUBLIC_API static inline
# elif defined(_MSC_VER)
# define XXH_PUBLIC_API static __inline
# else
# define XXH_PUBLIC_API static /* this version may generate warnings for unused static functions; disable the relevant warning */
# endif
#else
# define XXH_PUBLIC_API /* do nothing */
#endif /* XXH_PRIVATE_API */
/*!XXH_NAMESPACE, aka Namespace Emulation :
If you want to include _and expose_ xxHash functions from within your own library,
but also want to avoid symbol collisions with other libraries which may also include xxHash,
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).
Note that no change is required within the calling program as long as it includes `xxhash.h` :
regular symbol name will be automatically translated by this header.
*/
#ifdef XXH_NAMESPACE
# define XXH_CAT(A,B) A##B
# define XXH_NAME2(A,B) XXH_CAT(A,B)
# define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)
# define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)
# define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)
# define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)
# define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)
# define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)
# define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)
# define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)
# define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)
# define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)
# define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)
# define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)
# define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)
# define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)
# define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)
# define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)
# define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)
# define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)
# define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)
#endif
/* *************************************
* Version
***************************************/
#define XXH_VERSION_MAJOR 0
#define XXH_VERSION_MINOR 6
#define XXH_VERSION_RELEASE 2
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
/*-**********************************************************************
* 32-bits hash
************************************************************************/
typedef unsigned int XXH32_hash_t;
/*! XXH32() :
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
The memory between input & input+length must be valid (allocated and read-accessible).
"seed" can be used to alter the result predictably.
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
/*====== Streaming ======*/
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
/*
These functions generate the xxHash of an input provided in multiple segments.
Note that, for small input, they are slower than single-call functions, due to state management.
For small input, prefer `XXH32()` and `XXH64()` .
XXH state must first be allocated, using XXH*_createState() .
Start a new hash by initializing state with a seed, using XXH*_reset().
Then, feed the hash state by calling XXH*_update() as many times as necessary.
Obviously, input must be allocated and read accessible.
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
Finally, a hash value can be produced anytime, by using XXH*_digest().
This function returns the nn-bits hash as an int or long long.
It's still possible to continue inserting input into the hash state after a digest,
and generate some new hashes later on, by calling again XXH*_digest().
When done, free XXH state space if it was allocated dynamically.
*/
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
* These functions allow transformation of hash result into and from its canonical format.
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
*/
#ifndef XXH_NO_LONG_LONG
/*-**********************************************************************
* 64-bits hash
************************************************************************/
typedef unsigned long long XXH64_hash_t;
/*! XXH64() :
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
"seed" can be used to alter the result predictably.
This function runs faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
*/
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
/*====== Streaming ======*/
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
/*====== Canonical representation ======*/
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
#endif /* XXH_NO_LONG_LONG */
#ifdef XXH_STATIC_LINKING_ONLY
/* ================================================================================================
This section contains definitions which are not guaranteed to remain stable.
They may change in future versions, becoming incompatible with a different version of the library.
They shall only be used with static linking.
Never use these definitions in association with dynamic linking !
=================================================================================================== */
/* These definitions are only meant to allow allocation of XXH state
statically, on stack, or in a struct for example.
Do not use members directly. */
struct XXH32_state_s {
unsigned total_len_32;
unsigned large_len;
unsigned v1;
unsigned v2;
unsigned v3;
unsigned v4;
unsigned mem32[4]; /* buffer defined as U32 for alignment */
unsigned memsize;
unsigned reserved; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH32_state_t */
#ifndef XXH_NO_LONG_LONG
struct XXH64_state_s {
unsigned long long total_len;
unsigned long long v1;
unsigned long long v2;
unsigned long long v3;
unsigned long long v4;
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
unsigned memsize;
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
}; /* typedef'd to XXH64_state_t */
#endif
# ifdef XXH_PRIVATE_API
# include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */
# endif
#endif /* XXH_STATIC_LINKING_ONLY */
#if defined (__cplusplus)
}
#endif
#endif /* XXHASH_H_5627135585666179 */

View File

@ -0,0 +1,2 @@
DisableFormat: true
SortIncludes: false

View File

@ -0,0 +1,706 @@
/*
LZ4X - An optimized LZ4 compressor
Written and placed in the public domain by Ilya Muravyov
*/
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#define _CRT_DISABLE_PERFCRIT_LOCKS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NO_UTIME
#ifndef NO_UTIME
# include <sys/types.h>
# include <sys/stat.h>
# ifdef _MSC_VER
# include <sys/utime.h>
# else
# include <utime.h>
# endif
#endif
#ifndef _MSC_VER
# define _ftelli64 ftello64
#endif
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;
//FILE* g_in;
//FILE* g_out;
#define LZ4_MAGIC 0x184C2102
#define BLOCK_SIZE (8<<20) // 8 MB
#define PADDING_LITERALS 5
#define WINDOW_BITS 16
#define WINDOW_SIZE (1<<WINDOW_BITS)
#define WINDOW_MASK (WINDOW_SIZE-1)
#define MIN_MATCH 4
#define EXCESS (16+(BLOCK_SIZE/255))
static U8 g_buf[BLOCK_SIZE+BLOCK_SIZE+EXCESS];
#define MIN(a, b) (((a)<(b))?(a):(b))
#define MAX(a, b) (((a)>(b))?(a):(b))
#define LOAD_16(p) (*(const U16*)(&g_buf[p]))
#define LOAD_32(p) (*(const U32*)(&g_buf[p]))
#define STORE_16(p, x) (*(U16*)(&g_buf[p])=(x))
#define COPY_32(d, s) (*(U32*)(&g_buf[d])=LOAD_32(s))
#define HASH_BITS 18
#define HASH_SIZE (1<<HASH_BITS)
#define NIL (-1)
#define HASH_32(p) ((LOAD_32(p)*0x9E3779B9)>>(32-HASH_BITS))
static inline void wild_copy(int d, int s, int n)
{
COPY_32(d, s);
COPY_32(d+4, s+4);
for (int i=8; i<n; i+=8)
{
COPY_32(d+i, s+i);
COPY_32(d+4+i, s+4+i);
}
}
#if 0
void compress(const int max_chain)
{
static int head[HASH_SIZE];
static int tail[WINDOW_SIZE];
int n;
while ((n=fread(g_buf, 1, BLOCK_SIZE, g_in))>0)
{
for (int i=0; i<HASH_SIZE; ++i)
head[i]=NIL;
int op=BLOCK_SIZE;
int pp=0;
int p=0;
while (p<n)
{
int best_len=0;
int dist=0;
const int max_match=(n-PADDING_LITERALS)-p;
if (max_match>=MAX(12-PADDING_LITERALS, MIN_MATCH))
{
const int limit=MAX(p-WINDOW_SIZE, NIL);
int chain_len=max_chain;
int s=head[HASH_32(p)];
while (s>limit)
{
if (g_buf[s+best_len]==g_buf[p+best_len] && LOAD_32(s)==LOAD_32(p))
{
int len=MIN_MATCH;
while (len<max_match && g_buf[s+len]==g_buf[p+len])
++len;
if (len>best_len)
{
best_len=len;
dist=p-s;
if (len==max_match)
break;
}
}
if (--chain_len==0)
break;
s=tail[s&WINDOW_MASK];
}
}
if (best_len>=MIN_MATCH)
{
int len=best_len-MIN_MATCH;
const int nib=MIN(len, 15);
if (pp!=p)
{
const int run=p-pp;
if (run>=15)
{
g_buf[op++]=(15<<4)+nib;
int j=run-15;
for (; j>=255; j-=255)
g_buf[op++]=255;
g_buf[op++]=j;
}
else
g_buf[op++]=(run<<4)+nib;
wild_copy(op, pp, run);
op+=run;
}
else
g_buf[op++]=nib;
STORE_16(op, dist);
op+=2;
if (len>=15)
{
len-=15;
for (; len>=255; len-=255)
g_buf[op++]=255;
g_buf[op++]=len;
}
pp=p+best_len;
while (p<pp)
{
const U32 h=HASH_32(p);
tail[p&WINDOW_MASK]=head[h];
head[h]=p++;
}
}
else
{
const U32 h=HASH_32(p);
tail[p&WINDOW_MASK]=head[h];
head[h]=p++;
}
}
if (pp!=p)
{
const int run=p-pp;
if (run>=15)
{
g_buf[op++]=15<<4;
int j=run-15;
for (; j>=255; j-=255)
g_buf[op++]=255;
g_buf[op++]=j;
}
else
g_buf[op++]=run<<4;
wild_copy(op, pp, run);
op+=run;
}
const int comp_len=op-BLOCK_SIZE;
fwrite(&comp_len, 1, sizeof(comp_len), g_out);
fwrite(&g_buf[BLOCK_SIZE], 1, comp_len, g_out);
fprintf(stderr, "%lld -> %lld\r", _ftelli64(g_in), _ftelli64(g_out));
}
}
void compress_optimal()
{
static int head[HASH_SIZE];
static int nodes[WINDOW_SIZE][2];
static struct
{
int cum;
int len;
int dist;
} path[BLOCK_SIZE+1];
int n;
while ((n=fread(g_buf, 1, BLOCK_SIZE, g_in))>0)
{
// Pass 1: Find all matches
for (int i=0; i<HASH_SIZE; ++i)
head[i]=NIL;
for (int p=0; p<n; ++p)
{
int best_len=0;
int dist=0;
const int max_match=(n-PADDING_LITERALS)-p;
if (max_match>=MAX(12-PADDING_LITERALS, MIN_MATCH))
{
const int limit=MAX(p-WINDOW_SIZE, NIL);
int* left=&nodes[p&WINDOW_MASK][1];
int* right=&nodes[p&WINDOW_MASK][0];
int left_len=0;
int right_len=0;
const U32 h=HASH_32(p);
int s=head[h];
head[h]=p;
while (s>limit)
{
int len=MIN(left_len, right_len);
if (g_buf[s+len]==g_buf[p+len])
{
while (++len<max_match && g_buf[s+len]==g_buf[p+len]);
if (len>best_len)
{
best_len=len;
dist=p-s;
if (len==max_match || len>=(1<<16))
break;
}
}
if (g_buf[s+len]<g_buf[p+len])
{
*right=s;
right=&nodes[s&WINDOW_MASK][1];
s=*right;
right_len=len;
}
else
{
*left=s;
left=&nodes[s&WINDOW_MASK][0];
s=*left;
left_len=len;
}
}
*left=NIL;
*right=NIL;
}
path[p].len=best_len;
path[p].dist=dist;
}
// Pass 2: Build the shortest path
path[n].cum=0;
int count=15;
for (int p=n-1; p>0; --p)
{
int c0=path[p+1].cum+1;
if (--count==0)
{
count=255;
++c0;
}
int len=path[p].len;
if (len>=MIN_MATCH)
{
int c1=1<<30;
const int j=MAX(len-255, MIN_MATCH);
for (int i=len; i>=j; --i)
{
int tmp=path[p+i].cum+3;
if (i>=(15+MIN_MATCH))
tmp+=1+((i-(15+MIN_MATCH))/255);
if (tmp<c1)
{
c1=tmp;
len=i;
}
}
if (c1<=c0)
{
path[p].cum=c1;
path[p].len=len;
count=15;
}
else
{
path[p].cum=c0;
path[p].len=0;
}
}
else
path[p].cum=c0;
}
// Pass 3: Output the codes
int op=BLOCK_SIZE;
int pp=0;
int p=0;
while (p<n)
{
if (path[p].len>=MIN_MATCH)
{
int len=path[p].len-MIN_MATCH;
const int nib=MIN(len, 15);
if (pp!=p)
{
const int run=p-pp;
if (run>=15)
{
g_buf[op++]=(15<<4)+nib;
int j=run-15;
for (; j>=255; j-=255)
g_buf[op++]=255;
g_buf[op++]=j;
}
else
g_buf[op++]=(run<<4)+nib;
wild_copy(op, pp, run);
op+=run;
}
else
g_buf[op++]=nib;
STORE_16(op, path[p].dist);
op+=2;
if (len>=15)
{
len-=15;
for (; len>=255; len-=255)
g_buf[op++]=255;
g_buf[op++]=len;
}
p+=path[p].len;
pp=p;
}
else
++p;
}
if (pp!=p)
{
const int run=p-pp;
if (run>=15)
{
g_buf[op++]=15<<4;
int j=run-15;
for (; j>=255; j-=255)
g_buf[op++]=255;
g_buf[op++]=j;
}
else
g_buf[op++]=run<<4;
wild_copy(op, pp, run);
op+=run;
}
const int comp_len=op-BLOCK_SIZE;
fwrite(&comp_len, 1, sizeof(comp_len), g_out);
fwrite(&g_buf[BLOCK_SIZE], 1, comp_len, g_out);
fprintf(stderr, "%lld -> %lld\r", _ftelli64(g_in), _ftelli64(g_out));
}
}
#endif
static size_t kread(void* dst, size_t size, const char* src, size_t* offset, size_t compressedSize) {
size_t realSize = MIN(size, compressedSize - *offset);
memcpy(dst, &src[*offset], realSize);
*offset += realSize;
return realSize;
}
static size_t kwrite(void* src, size_t size, char* dst, size_t* offset, int maxOutputSize) {
size_t realSize = MIN(size, maxOutputSize - *offset);
memcpy(&dst[*offset], src, size);
*offset += realSize;
return realSize;
}
//int decompress()
#ifdef KINC_LZ4X
#include <kinc/error.h>
int LZ4_decompress_safe(const char *source, char *buf, int compressedSize, int maxOutputSize)
{
size_t read_offset = 0;
size_t write_offset = 0;
int comp_len;
while (kread(&comp_len, sizeof(comp_len), source, &read_offset, compressedSize)>0)
{
if (comp_len<2 || comp_len>(BLOCK_SIZE+EXCESS)
|| kread(&g_buf[BLOCK_SIZE], comp_len, source, &read_offset, compressedSize)!=comp_len)
return -1;
int p=0;
int ip=BLOCK_SIZE;
const int ip_end=ip+comp_len;
for (;;)
{
const int token=g_buf[ip++];
if (token>=16)
{
int run=token>>4;
if (run==15)
{
for (;;)
{
const int c=g_buf[ip++];
run+=c;
if (c!=255)
break;
}
}
if ((p+run)>BLOCK_SIZE)
return -1;
wild_copy(p, ip, run);
p+=run;
ip+=run;
if (ip>=ip_end)
break;
}
int s=p-LOAD_16(ip);
ip+=2;
if (s<0)
return -1;
int len=(token&15)+MIN_MATCH;
if (len==(15+MIN_MATCH))
{
for (;;)
{
const int c=g_buf[ip++];
len+=c;
if (c!=255)
break;
}
}
if ((p+len)>BLOCK_SIZE)
return -1;
if ((p-s)>=4)
{
wild_copy(p, s, len);
p+=len;
}
else
{
while (len--!=0)
g_buf[p++]=g_buf[s++];
}
}
if (kwrite(g_buf, p, buf, &write_offset, maxOutputSize)!=p)
{
kinc_error_message("Fwrite() failed");
return -1;
}
}
return 0;
}
#endif
#if 0
int main(int argc, char** argv)
{
const clock_t start=clock();
int level=4;
bool do_decomp=false;
bool overwrite=false;
while (argc>1 && *argv[1]=='-')
{
for (int i=1; argv[1][i]!='\0'; ++i)
{
switch (argv[1][i])
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
level=argv[1][i]-'0';
break;
case 'd':
do_decomp=true;
break;
case 'f':
overwrite=true;
break;
default:
fprintf(stderr, "Unknown option: -%c\n", argv[1][i]);
exit(1);
}
}
--argc;
++argv;
}
if (argc<2)
{
fprintf(stderr,
"LZ4X - An optimized LZ4 compressor, v1.60\n"
"Written and placed in the public domain by Ilya Muravyov\n"
"\n"
"Usage: LZ4X [options] infile [outfile]\n"
"\n"
"Options:\n"
" -1 Compress faster\n"
" -9 Compress better\n"
" -d Decompress\n"
" -f Force overwrite of output file\n");
exit(1);
}
g_in=fopen(argv[1], "rb");
if (!g_in)
{
perror(argv[1]);
exit(1);
}
char out_name[FILENAME_MAX];
if (argc<3)
{
strcpy(out_name, argv[1]);
if (do_decomp)
{
const int p=strlen(out_name)-4;
if (p>0 && strcmp(&out_name[p], ".lz4")==0)
out_name[p]='\0';
else
strcat(out_name, ".out");
}
else
strcat(out_name, ".lz4");
}
else
strcpy(out_name, argv[2]);
if (!overwrite)
{
FILE* f=fopen(out_name, "rb");
if (f)
{
fclose(f);
fprintf(stderr, "%s already exists. Overwrite (y/n)? ", out_name);
fflush(stderr);
if (getchar()!='y')
{
fprintf(stderr, "Not overwritten\n");
exit(1);
}
}
}
if (do_decomp)
{
int magic;
fread(&magic, 1, sizeof(magic), g_in);
if (magic!=LZ4_MAGIC)
{
fprintf(stderr, "%s: Not in Legacy format\n", argv[1]);
exit(1);
}
g_out=fopen(out_name, "wb");
if (!g_out)
{
perror(out_name);
exit(1);
}
fprintf(stderr, "Decompressing %s:\n", argv[1]);
if (decompress()!=0)
{
fprintf(stderr, "%s: Corrupt input\n", argv[1]);
exit(1);
}
}
else
{
g_out=fopen(out_name, "wb");
if (!g_out)
{
perror(out_name);
exit(1);
}
const int magic=LZ4_MAGIC;
fwrite(&magic, 1, sizeof(magic), g_out);
fprintf(stderr, "Compressing %s:\n", argv[1]);
if (level==9)
compress_optimal();
else
compress((level<8)?1<<level:WINDOW_SIZE);
}
fprintf(stderr, "%lld -> %lld in %1.3f sec\n", _ftelli64(g_in),
_ftelli64(g_out), double(clock()-start)/CLOCKS_PER_SEC);
fclose(g_in);
fclose(g_out);
#ifndef NO_UTIME
struct _stati64 sb;
if (_stati64(argv[1], &sb)!=0)
{
perror("Stat() failed");
exit(1);
}
struct utimbuf ub;
ub.actime=sb.st_atime;
ub.modtime=sb.st_mtime;
if (utime(out_name, &ub)!=0)
{
perror("Utime() failed");
exit(1);
}
#endif
return 0;
}
#endif

View File

@ -0,0 +1,301 @@
/* NEON implementation of sin, cos, exp and log
Inspired by Intel Approximate Math library, and based on the
corresponding algorithms of the cephes math library
*/
/* Copyright (C) 2011 Julien Pommier
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.
(this is the zlib license)
*/
#include <arm_neon.h>
typedef float32x4_t v4sf; // vector of 4 float
typedef uint32x4_t v4su; // vector of 4 uint32
typedef int32x4_t v4si; // vector of 4 uint32
#define c_inv_mant_mask ~0x7f800000u
#define c_cephes_SQRTHF 0.707106781186547524
#define c_cephes_log_p0 7.0376836292E-2
#define c_cephes_log_p1 - 1.1514610310E-1
#define c_cephes_log_p2 1.1676998740E-1
#define c_cephes_log_p3 - 1.2420140846E-1
#define c_cephes_log_p4 + 1.4249322787E-1
#define c_cephes_log_p5 - 1.6668057665E-1
#define c_cephes_log_p6 + 2.0000714765E-1
#define c_cephes_log_p7 - 2.4999993993E-1
#define c_cephes_log_p8 + 3.3333331174E-1
#define c_cephes_log_q1 -2.12194440e-4
#define c_cephes_log_q2 0.693359375
/* natural logarithm computed for 4 simultaneous float
return NaN for x <= 0
*/
v4sf log_ps(v4sf x) {
v4sf one = vdupq_n_f32(1);
x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */
v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0));
v4si ux = vreinterpretq_s32_f32(x);
v4si emm0 = vshrq_n_s32(ux, 23);
/* keep only the fractional part */
ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask));
ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f)));
x = vreinterpretq_f32_s32(ux);
emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f));
v4sf e = vcvtq_f32_s32(emm0);
e = vaddq_f32(e, one);
/* part2:
if( x < SQRTHF ) {
e -= 1;
x = x + x - 1.0;
} else { x = x - 1.0; }
*/
v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF));
v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask));
x = vsubq_f32(x, one);
e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask)));
x = vaddq_f32(x, tmp);
v4sf z = vmulq_f32(x,x);
v4sf y = vdupq_n_f32(c_cephes_log_p0);
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8));
y = vmulq_f32(y, x);
y = vmulq_f32(y, z);
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1));
y = vaddq_f32(y, tmp);
tmp = vmulq_f32(z, vdupq_n_f32(0.5f));
y = vsubq_f32(y, tmp);
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2));
x = vaddq_f32(x, y);
x = vaddq_f32(x, tmp);
x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN
return x;
}
#define c_exp_hi 88.3762626647949f
#define c_exp_lo -88.3762626647949f
#define c_cephes_LOG2EF 1.44269504088896341
#define c_cephes_exp_C1 0.693359375
#define c_cephes_exp_C2 -2.12194440e-4
#define c_cephes_exp_p0 1.9875691500E-4
#define c_cephes_exp_p1 1.3981999507E-3
#define c_cephes_exp_p2 8.3334519073E-3
#define c_cephes_exp_p3 4.1665795894E-2
#define c_cephes_exp_p4 1.6666665459E-1
#define c_cephes_exp_p5 5.0000001201E-1
/* exp() computed for 4 float at once */
v4sf exp_ps(v4sf x) {
v4sf tmp, fx;
v4sf one = vdupq_n_f32(1);
x = vminq_f32(x, vdupq_n_f32(c_exp_hi));
x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo));
/* express exp(x) as exp(g + n*log(2)) */
fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF));
/* perform a floorf */
tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx));
/* if greater, substract 1 */
v4su mask = vcgtq_f32(tmp, fx);
mask = vandq_u32(mask, vreinterpretq_u32_f32(one));
fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask));
tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1));
v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2));
x = vsubq_f32(x, tmp);
x = vsubq_f32(x, z);
static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 };
v4sf y = vld1q_dup_f32(cephes_exp_p+0);
v4sf c1 = vld1q_dup_f32(cephes_exp_p+1);
v4sf c2 = vld1q_dup_f32(cephes_exp_p+2);
v4sf c3 = vld1q_dup_f32(cephes_exp_p+3);
v4sf c4 = vld1q_dup_f32(cephes_exp_p+4);
v4sf c5 = vld1q_dup_f32(cephes_exp_p+5);
y = vmulq_f32(y, x);
z = vmulq_f32(x,x);
y = vaddq_f32(y, c1);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c2);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c3);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c4);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c5);
y = vmulq_f32(y, z);
y = vaddq_f32(y, x);
y = vaddq_f32(y, one);
/* build 2^n */
int32x4_t mm;
mm = vcvtq_s32_f32(fx);
mm = vaddq_s32(mm, vdupq_n_s32(0x7f));
mm = vshlq_n_s32(mm, 23);
v4sf pow2n = vreinterpretq_f32_s32(mm);
y = vmulq_f32(y, pow2n);
return y;
}
#define c_minus_cephes_DP1 -0.78515625
#define c_minus_cephes_DP2 -2.4187564849853515625e-4
#define c_minus_cephes_DP3 -3.77489497744594108e-8
#define c_sincof_p0 -1.9515295891E-4
#define c_sincof_p1 8.3321608736E-3
#define c_sincof_p2 -1.6666654611E-1
#define c_coscof_p0 2.443315711809948E-005
#define c_coscof_p1 -1.388731625493765E-003
#define c_coscof_p2 4.166664568298827E-002
#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI
/* evaluation of 4 sines & cosines at once.
The code is the exact rewriting of the cephes sinf function.
Precision is excellent as long as x < 8192 (I did not bother to
take into account the special handling they have for greater values
-- it does not return garbage for arguments over 8192, though, but
the extra precision is missing).
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
surprising but correct result.
Note also that when you compute sin(x), cos(x) is available at
almost no extra price so both sin_ps and cos_ps make use of
sincos_ps..
*/
void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x
v4sf xmm1, xmm2, xmm3, y;
v4su emm2;
v4su sign_mask_sin, sign_mask_cos;
sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0));
x = vabsq_f32(x);
/* scale by 4/Pi */
y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI));
/* store the integer part of y in mm0 */
emm2 = vcvtq_u32_f32(y);
/* j=(j+1) & (~1) (see the cephes sources) */
emm2 = vaddq_u32(emm2, vdupq_n_u32(1));
emm2 = vandq_u32(emm2, vdupq_n_u32(~1));
y = vcvtq_f32_u32(emm2);
/* get the polynom selection mask
there is one polynom for 0 <= x <= Pi/4
and another one for Pi/4<x<=Pi/2
Both branches will be computed.
*/
v4su poly_mask = vtstq_u32(emm2, vdupq_n_u32(2));
/* The magic pass: "Extended precision modular arithmetic"
x = ((x - y * DP1) - y * DP2) - y * DP3; */
xmm1 = vmulq_n_f32(y, c_minus_cephes_DP1);
xmm2 = vmulq_n_f32(y, c_minus_cephes_DP2);
xmm3 = vmulq_n_f32(y, c_minus_cephes_DP3);
x = vaddq_f32(x, xmm1);
x = vaddq_f32(x, xmm2);
x = vaddq_f32(x, xmm3);
sign_mask_sin = veorq_u32(sign_mask_sin, vtstq_u32(emm2, vdupq_n_u32(4)));
sign_mask_cos = vtstq_u32(vsubq_u32(emm2, vdupq_n_u32(2)), vdupq_n_u32(4));
/* Evaluate the first polynom (0 <= x <= Pi/4) in y1,
and the second polynom (Pi/4 <= x <= 0) in y2 */
v4sf z = vmulq_f32(x,x);
v4sf y1, y2;
y1 = vmulq_n_f32(z, c_coscof_p0);
y2 = vmulq_n_f32(z, c_sincof_p0);
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p1));
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p1));
y1 = vmulq_f32(y1, z);
y2 = vmulq_f32(y2, z);
y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p2));
y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p2));
y1 = vmulq_f32(y1, z);
y2 = vmulq_f32(y2, z);
y1 = vmulq_f32(y1, z);
y2 = vmulq_f32(y2, x);
y1 = vsubq_f32(y1, vmulq_f32(z, vdupq_n_f32(0.5f)));
y2 = vaddq_f32(y2, x);
y1 = vaddq_f32(y1, vdupq_n_f32(1));
/* select the correct result from the two polynoms */
v4sf ys = vbslq_f32(poly_mask, y1, y2);
v4sf yc = vbslq_f32(poly_mask, y2, y1);
*ysin = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys);
*ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc));
}
v4sf sin_ps(v4sf x) {
v4sf ysin, ycos;
sincos_ps(x, &ysin, &ycos);
return ysin;
}
v4sf cos_ps(v4sf x) {
v4sf ysin, ycos;
sincos_ps(x, &ysin, &ycos);
return ycos;
}

View File

@ -0,0 +1,711 @@
/* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log
Inspired by Intel Approximate Math library, and based on the
corresponding algorithms of the cephes math library
The default is to use the SSE1 version. If you define USE_SSE2 the
the SSE2 intrinsics will be used in place of the MMX intrinsics. Do
not expect any significant performance improvement with SSE2.
*/
/* Copyright (C) 2007 Julien Pommier
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.
(this is the zlib license)
*/
#include <xmmintrin.h>
/* yes I know, the top of this file is quite ugly */
#ifdef _MSC_VER /* visual c++ */
# define ALIGN16_BEG __declspec(align(16))
# define ALIGN16_END
#else /* gcc or icc */
# define ALIGN16_BEG
# define ALIGN16_END __attribute__((aligned(16)))
#endif
/* __m128 is ugly to write */
typedef __m128 v4sf; // vector of 4 float (sse1)
#ifdef USE_SSE2
# include <emmintrin.h>
typedef __m128i v4si; // vector of 4 int (sse2)
#else
typedef __m64 v2si; // vector of 2 int (mmx)
#endif
/* declare some SSE constants -- why can't I figure a better way to do that? */
#define _PS_CONST(Name, Val) \
static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
#define _PI32_CONST(Name, Val) \
static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
#define _PS_CONST_TYPE(Name, Type, Val) \
static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val }
_PS_CONST(1 , 1.0f);
_PS_CONST(0p5, 0.5f);
/* the smallest non denormalized float number */
_PS_CONST_TYPE(min_norm_pos, int, 0x00800000);
_PS_CONST_TYPE(mant_mask, int, 0x7f800000);
_PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000);
_PS_CONST_TYPE(sign_mask, int, (int)0x80000000);
_PS_CONST_TYPE(inv_sign_mask, int, ~0x80000000);
_PI32_CONST(1, 1);
_PI32_CONST(inv1, ~1);
_PI32_CONST(2, 2);
_PI32_CONST(4, 4);
_PI32_CONST(0x7f, 0x7f);
_PS_CONST(cephes_SQRTHF, 0.707106781186547524);
_PS_CONST(cephes_log_p0, 7.0376836292E-2);
_PS_CONST(cephes_log_p1, - 1.1514610310E-1);
_PS_CONST(cephes_log_p2, 1.1676998740E-1);
_PS_CONST(cephes_log_p3, - 1.2420140846E-1);
_PS_CONST(cephes_log_p4, + 1.4249322787E-1);
_PS_CONST(cephes_log_p5, - 1.6668057665E-1);
_PS_CONST(cephes_log_p6, + 2.0000714765E-1);
_PS_CONST(cephes_log_p7, - 2.4999993993E-1);
_PS_CONST(cephes_log_p8, + 3.3333331174E-1);
_PS_CONST(cephes_log_q1, -2.12194440e-4);
_PS_CONST(cephes_log_q2, 0.693359375);
#ifndef USE_SSE2
typedef union xmm_mm_union {
__m128 xmm;
__m64 mm[2];
} xmm_mm_union;
#define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \
xmm_mm_union u; u.xmm = xmm_; \
mm0_ = u.mm[0]; \
mm1_ = u.mm[1]; \
}
#define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \
xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \
}
#endif // USE_SSE2
/* natural logarithm computed for 4 simultaneous float
return NaN for x <= 0
*/
v4sf log_ps(v4sf x) {
#ifdef USE_SSE2
v4si emm0;
#else
v2si mm0, mm1;
#endif
v4sf one = *(v4sf*)_ps_1;
v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps());
x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */
#ifndef USE_SSE2
/* part 1: x = frexpf(x, &e); */
COPY_XMM_TO_MM(x, mm0, mm1);
mm0 = _mm_srli_pi32(mm0, 23);
mm1 = _mm_srli_pi32(mm1, 23);
#else
emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23);
#endif
/* keep only the fractional part */
x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask);
x = _mm_or_ps(x, *(v4sf*)_ps_0p5);
#ifndef USE_SSE2
/* now e=mm0:mm1 contain the really base-2 exponent */
mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f);
mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f);
v4sf e = _mm_cvtpi32x2_ps(mm0, mm1);
_mm_empty(); /* bye bye mmx */
#else
emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f);
v4sf e = _mm_cvtepi32_ps(emm0);
#endif
e = _mm_add_ps(e, one);
/* part2:
if( x < SQRTHF ) {
e -= 1;
x = x + x - 1.0;
} else { x = x - 1.0; }
*/
v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF);
v4sf tmp = _mm_and_ps(x, mask);
x = _mm_sub_ps(x, one);
e = _mm_sub_ps(e, _mm_and_ps(one, mask));
x = _mm_add_ps(x, tmp);
v4sf z = _mm_mul_ps(x,x);
v4sf y = *(v4sf*)_ps_cephes_log_p0;
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8);
y = _mm_mul_ps(y, x);
y = _mm_mul_ps(y, z);
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1);
y = _mm_add_ps(y, tmp);
tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
y = _mm_sub_ps(y, tmp);
tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2);
x = _mm_add_ps(x, y);
x = _mm_add_ps(x, tmp);
x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN
return x;
}
_PS_CONST(exp_hi, 88.3762626647949f);
_PS_CONST(exp_lo, -88.3762626647949f);
_PS_CONST(cephes_LOG2EF, 1.44269504088896341);
_PS_CONST(cephes_exp_C1, 0.693359375);
_PS_CONST(cephes_exp_C2, -2.12194440e-4);
_PS_CONST(cephes_exp_p0, 1.9875691500E-4);
_PS_CONST(cephes_exp_p1, 1.3981999507E-3);
_PS_CONST(cephes_exp_p2, 8.3334519073E-3);
_PS_CONST(cephes_exp_p3, 4.1665795894E-2);
_PS_CONST(cephes_exp_p4, 1.6666665459E-1);
_PS_CONST(cephes_exp_p5, 5.0000001201E-1);
v4sf exp_ps(v4sf x) {
v4sf tmp = _mm_setzero_ps(), fx;
#ifdef USE_SSE2
v4si emm0;
#else
v2si mm0, mm1;
#endif
v4sf one = *(v4sf*)_ps_1;
x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi);
x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo);
/* express exp(x) as exp(g + n*log(2)) */
fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF);
fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5);
/* how to perform a floorf with SSE: just below */
#ifndef USE_SSE2
/* step 1 : cast to int */
tmp = _mm_movehl_ps(tmp, fx);
mm0 = _mm_cvttps_pi32(fx);
mm1 = _mm_cvttps_pi32(tmp);
/* step 2 : cast back to float */
tmp = _mm_cvtpi32x2_ps(mm0, mm1);
#else
emm0 = _mm_cvttps_epi32(fx);
tmp = _mm_cvtepi32_ps(emm0);
#endif
/* if greater, substract 1 */
v4sf mask = _mm_cmpgt_ps(tmp, fx);
mask = _mm_and_ps(mask, one);
fx = _mm_sub_ps(tmp, mask);
tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1);
v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2);
x = _mm_sub_ps(x, tmp);
x = _mm_sub_ps(x, z);
z = _mm_mul_ps(x,x);
v4sf y = *(v4sf*)_ps_cephes_exp_p0;
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4);
y = _mm_mul_ps(y, x);
y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, x);
y = _mm_add_ps(y, one);
/* build 2^n */
#ifndef USE_SSE2
z = _mm_movehl_ps(z, fx);
mm0 = _mm_cvttps_pi32(fx);
mm1 = _mm_cvttps_pi32(z);
mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f);
mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f);
mm0 = _mm_slli_pi32(mm0, 23);
mm1 = _mm_slli_pi32(mm1, 23);
v4sf pow2n;
COPY_MM_TO_XMM(mm0, mm1, pow2n);
_mm_empty();
#else
emm0 = _mm_cvttps_epi32(fx);
emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f);
emm0 = _mm_slli_epi32(emm0, 23);
v4sf pow2n = _mm_castsi128_ps(emm0);
#endif
y = _mm_mul_ps(y, pow2n);
return y;
}
_PS_CONST(minus_cephes_DP1, -0.78515625);
_PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4);
_PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8);
_PS_CONST(sincof_p0, -1.9515295891E-4);
_PS_CONST(sincof_p1, 8.3321608736E-3);
_PS_CONST(sincof_p2, -1.6666654611E-1);
_PS_CONST(coscof_p0, 2.443315711809948E-005);
_PS_CONST(coscof_p1, -1.388731625493765E-003);
_PS_CONST(coscof_p2, 4.166664568298827E-002);
_PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI
/* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so
it runs also on old athlons XPs and the pentium III of your grand
mother.
The code is the exact rewriting of the cephes sinf function.
Precision is excellent as long as x < 8192 (I did not bother to
take into account the special handling they have for greater values
-- it does not return garbage for arguments over 8192, though, but
the extra precision is missing).
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
surprising but correct result.
Performance is also surprisingly good, 1.33 times faster than the
macos vsinf SSE2 function, and 1.5 times faster than the
__vrs4_sinf of amd's ACML (which is only available in 64 bits). Not
too bad for an SSE1 function (with no special tuning) !
However the latter libraries probably have a much better handling of NaN,
Inf, denormalized and other special arguments..
On my core 1 duo, the execution of this function takes approximately 95 cycles.
From what I have observed on the experiments with Intel AMath lib, switching to an
SSE2 version would improve the perf by only 10%.
Since it is based on SSE intrinsics, it has to be compiled at -O2 to
deliver full speed.
*/
v4sf sin_ps(v4sf x) { // any x
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y;
#ifdef USE_SSE2
v4si emm0, emm2;
#else
v2si mm0, mm1, mm2, mm3;
#endif
sign_bit = x;
/* take the absolute value */
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
/* extract the sign bit (upper one) */
sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask);
/* scale by 4/Pi */
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
#ifdef USE_SSE2
/* store the integer part of y in mm0 */
emm2 = _mm_cvttps_epi32(y);
/* j=(j+1) & (~1) (see the cephes sources) */
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
y = _mm_cvtepi32_ps(emm2);
/* get the swap sign flag */
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
emm0 = _mm_slli_epi32(emm0, 29);
/* get the polynom selection mask
there is one polynom for 0 <= x <= Pi/4
and another one for Pi/4<x<=Pi/2
Both branches will be computed.
*/
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
v4sf swap_sign_bit = _mm_castsi128_ps(emm0);
v4sf poly_mask = _mm_castsi128_ps(emm2);
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
#else
/* store the integer part of y in mm0:mm1 */
xmm2 = _mm_movehl_ps(xmm2, y);
mm2 = _mm_cvttps_pi32(y);
mm3 = _mm_cvttps_pi32(xmm2);
/* j=(j+1) & (~1) (see the cephes sources) */
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
y = _mm_cvtpi32x2_ps(mm2, mm3);
/* get the swap sign flag */
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
mm0 = _mm_slli_pi32(mm0, 29);
mm1 = _mm_slli_pi32(mm1, 29);
/* get the polynom selection mask */
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
v4sf swap_sign_bit, poly_mask;
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit);
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
sign_bit = _mm_xor_ps(sign_bit, swap_sign_bit);
_mm_empty(); /* good-bye mmx */
#endif
/* The magic pass: "Extended precision modular arithmetic"
x = ((x - y * DP1) - y * DP2) - y * DP3; */
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
xmm1 = _mm_mul_ps(y, xmm1);
xmm2 = _mm_mul_ps(y, xmm2);
xmm3 = _mm_mul_ps(y, xmm3);
x = _mm_add_ps(x, xmm1);
x = _mm_add_ps(x, xmm2);
x = _mm_add_ps(x, xmm3);
/* Evaluate the first polynom (0 <= x <= Pi/4) */
y = *(v4sf*)_ps_coscof_p0;
v4sf z = _mm_mul_ps(x,x);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
y = _mm_mul_ps(y, z);
y = _mm_mul_ps(y, z);
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
y = _mm_sub_ps(y, tmp);
y = _mm_add_ps(y, *(v4sf*)_ps_1);
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
v4sf y2 = *(v4sf*)_ps_sincof_p0;
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_mul_ps(y2, x);
y2 = _mm_add_ps(y2, x);
/* select the correct result from the two polynoms */
xmm3 = poly_mask;
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
y = _mm_andnot_ps(xmm3, y);
y = _mm_add_ps(y,y2);
/* update the sign */
y = _mm_xor_ps(y, sign_bit);
return y;
}
/* almost the same as sin_ps */
v4sf cos_ps(v4sf x) { // any x
v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, y;
#ifdef USE_SSE2
v4si emm0, emm2;
#else
v2si mm0, mm1, mm2, mm3;
#endif
/* take the absolute value */
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
/* scale by 4/Pi */
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
#ifdef USE_SSE2
/* store the integer part of y in mm0 */
emm2 = _mm_cvttps_epi32(y);
/* j=(j+1) & (~1) (see the cephes sources) */
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
y = _mm_cvtepi32_ps(emm2);
emm2 = _mm_sub_epi32(emm2, *(v4si*)_pi32_2);
/* get the swap sign flag */
emm0 = _mm_andnot_si128(emm2, *(v4si*)_pi32_4);
emm0 = _mm_slli_epi32(emm0, 29);
/* get the polynom selection mask */
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
v4sf sign_bit = _mm_castsi128_ps(emm0);
v4sf poly_mask = _mm_castsi128_ps(emm2);
#else
/* store the integer part of y in mm0:mm1 */
xmm2 = _mm_movehl_ps(xmm2, y);
mm2 = _mm_cvttps_pi32(y);
mm3 = _mm_cvttps_pi32(xmm2);
/* j=(j+1) & (~1) (see the cephes sources) */
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
y = _mm_cvtpi32x2_ps(mm2, mm3);
mm2 = _mm_sub_pi32(mm2, *(v2si*)_pi32_2);
mm3 = _mm_sub_pi32(mm3, *(v2si*)_pi32_2);
/* get the swap sign flag in mm0:mm1 and the
polynom selection mask in mm2:mm3 */
mm0 = _mm_andnot_si64(mm2, *(v2si*)_pi32_4);
mm1 = _mm_andnot_si64(mm3, *(v2si*)_pi32_4);
mm0 = _mm_slli_pi32(mm0, 29);
mm1 = _mm_slli_pi32(mm1, 29);
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
v4sf sign_bit, poly_mask;
COPY_MM_TO_XMM(mm0, mm1, sign_bit);
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
_mm_empty(); /* good-bye mmx */
#endif
/* The magic pass: "Extended precision modular arithmetic"
x = ((x - y * DP1) - y * DP2) - y * DP3; */
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
xmm1 = _mm_mul_ps(y, xmm1);
xmm2 = _mm_mul_ps(y, xmm2);
xmm3 = _mm_mul_ps(y, xmm3);
x = _mm_add_ps(x, xmm1);
x = _mm_add_ps(x, xmm2);
x = _mm_add_ps(x, xmm3);
/* Evaluate the first polynom (0 <= x <= Pi/4) */
y = *(v4sf*)_ps_coscof_p0;
v4sf z = _mm_mul_ps(x,x);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
y = _mm_mul_ps(y, z);
y = _mm_mul_ps(y, z);
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
y = _mm_sub_ps(y, tmp);
y = _mm_add_ps(y, *(v4sf*)_ps_1);
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
v4sf y2 = *(v4sf*)_ps_sincof_p0;
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_mul_ps(y2, x);
y2 = _mm_add_ps(y2, x);
/* select the correct result from the two polynoms */
xmm3 = poly_mask;
y2 = _mm_and_ps(xmm3, y2); //, xmm3);
y = _mm_andnot_ps(xmm3, y);
y = _mm_add_ps(y,y2);
/* update the sign */
y = _mm_xor_ps(y, sign_bit);
return y;
}
/* since sin_ps and cos_ps are almost identical, sincos_ps could replace both of them..
it is almost as fast, and gives you a free cosine with your sine */
void sincos_ps(v4sf x, v4sf *s, v4sf *c) {
v4sf xmm1, xmm2, xmm3 = _mm_setzero_ps(), sign_bit_sin, y;
#ifdef USE_SSE2
v4si emm0, emm2, emm4;
#else
v2si mm0, mm1, mm2, mm3, mm4, mm5;
#endif
sign_bit_sin = x;
/* take the absolute value */
x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask);
/* extract the sign bit (upper one) */
sign_bit_sin = _mm_and_ps(sign_bit_sin, *(v4sf*)_ps_sign_mask);
/* scale by 4/Pi */
y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI);
#ifdef USE_SSE2
/* store the integer part of y in emm2 */
emm2 = _mm_cvttps_epi32(y);
/* j=(j+1) & (~1) (see the cephes sources) */
emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1);
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1);
y = _mm_cvtepi32_ps(emm2);
emm4 = emm2;
/* get the swap sign flag for the sine */
emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4);
emm0 = _mm_slli_epi32(emm0, 29);
v4sf swap_sign_bit_sin = _mm_castsi128_ps(emm0);
/* get the polynom selection mask for the sine*/
emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_2);
emm2 = _mm_cmpeq_epi32(emm2, _mm_setzero_si128());
v4sf poly_mask = _mm_castsi128_ps(emm2);
#else
/* store the integer part of y in mm2:mm3 */
xmm3 = _mm_movehl_ps(xmm3, y);
mm2 = _mm_cvttps_pi32(y);
mm3 = _mm_cvttps_pi32(xmm3);
/* j=(j+1) & (~1) (see the cephes sources) */
mm2 = _mm_add_pi32(mm2, *(v2si*)_pi32_1);
mm3 = _mm_add_pi32(mm3, *(v2si*)_pi32_1);
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_inv1);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_inv1);
y = _mm_cvtpi32x2_ps(mm2, mm3);
mm4 = mm2;
mm5 = mm3;
/* get the swap sign flag for the sine */
mm0 = _mm_and_si64(mm2, *(v2si*)_pi32_4);
mm1 = _mm_and_si64(mm3, *(v2si*)_pi32_4);
mm0 = _mm_slli_pi32(mm0, 29);
mm1 = _mm_slli_pi32(mm1, 29);
v4sf swap_sign_bit_sin;
COPY_MM_TO_XMM(mm0, mm1, swap_sign_bit_sin);
/* get the polynom selection mask for the sine */
mm2 = _mm_and_si64(mm2, *(v2si*)_pi32_2);
mm3 = _mm_and_si64(mm3, *(v2si*)_pi32_2);
mm2 = _mm_cmpeq_pi32(mm2, _mm_setzero_si64());
mm3 = _mm_cmpeq_pi32(mm3, _mm_setzero_si64());
v4sf poly_mask;
COPY_MM_TO_XMM(mm2, mm3, poly_mask);
#endif
/* The magic pass: "Extended precision modular arithmetic"
x = ((x - y * DP1) - y * DP2) - y * DP3; */
xmm1 = *(v4sf*)_ps_minus_cephes_DP1;
xmm2 = *(v4sf*)_ps_minus_cephes_DP2;
xmm3 = *(v4sf*)_ps_minus_cephes_DP3;
xmm1 = _mm_mul_ps(y, xmm1);
xmm2 = _mm_mul_ps(y, xmm2);
xmm3 = _mm_mul_ps(y, xmm3);
x = _mm_add_ps(x, xmm1);
x = _mm_add_ps(x, xmm2);
x = _mm_add_ps(x, xmm3);
#ifdef USE_SSE2
emm4 = _mm_sub_epi32(emm4, *(v4si*)_pi32_2);
emm4 = _mm_andnot_si128(emm4, *(v4si*)_pi32_4);
emm4 = _mm_slli_epi32(emm4, 29);
v4sf sign_bit_cos = _mm_castsi128_ps(emm4);
#else
/* get the sign flag for the cosine */
mm4 = _mm_sub_pi32(mm4, *(v2si*)_pi32_2);
mm5 = _mm_sub_pi32(mm5, *(v2si*)_pi32_2);
mm4 = _mm_andnot_si64(mm4, *(v2si*)_pi32_4);
mm5 = _mm_andnot_si64(mm5, *(v2si*)_pi32_4);
mm4 = _mm_slli_pi32(mm4, 29);
mm5 = _mm_slli_pi32(mm5, 29);
v4sf sign_bit_cos;
COPY_MM_TO_XMM(mm4, mm5, sign_bit_cos);
_mm_empty(); /* good-bye mmx */
#endif
sign_bit_sin = _mm_xor_ps(sign_bit_sin, swap_sign_bit_sin);
/* Evaluate the first polynom (0 <= x <= Pi/4) */
v4sf z = _mm_mul_ps(x,x);
y = *(v4sf*)_ps_coscof_p0;
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p1);
y = _mm_mul_ps(y, z);
y = _mm_add_ps(y, *(v4sf*)_ps_coscof_p2);
y = _mm_mul_ps(y, z);
y = _mm_mul_ps(y, z);
v4sf tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5);
y = _mm_sub_ps(y, tmp);
y = _mm_add_ps(y, *(v4sf*)_ps_1);
/* Evaluate the second polynom (Pi/4 <= x <= 0) */
v4sf y2 = *(v4sf*)_ps_sincof_p0;
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p1);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_add_ps(y2, *(v4sf*)_ps_sincof_p2);
y2 = _mm_mul_ps(y2, z);
y2 = _mm_mul_ps(y2, x);
y2 = _mm_add_ps(y2, x);
/* select the correct result from the two polynoms */
xmm3 = poly_mask;
v4sf ysin2 = _mm_and_ps(xmm3, y2);
v4sf ysin1 = _mm_andnot_ps(xmm3, y);
y2 = _mm_sub_ps(y2,ysin2);
y = _mm_sub_ps(y, ysin1);
xmm1 = _mm_add_ps(ysin1,ysin2);
xmm2 = _mm_add_ps(y,y2);
/* update the sign */
*s = _mm_xor_ps(xmm1, sign_bit_sin);
*c = _mm_xor_ps(xmm2, sign_bit_cos);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

135
Kha/Kinc/Sources/kinc/log.h Normal file
View File

@ -0,0 +1,135 @@
#pragma once
#include <kinc/global.h>
#include <stdarg.h>
/*! \file log.h
\brief Contains basic logging functionality.
Logging functionality is similar to plain printf but provides some system-specific bonuses.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Pass this to kinc_log or kinc_log_args
/// </summary>
/// <remarks>
/// When used on Android the log level is converted to the equivalent
/// Android logging level. It is currently ignored on all other targets.
/// </remarks>
typedef enum { KINC_LOG_LEVEL_INFO, KINC_LOG_LEVEL_WARNING, KINC_LOG_LEVEL_ERROR } kinc_log_level_t;
/// <summary>
/// Logging function similar to printf including some system-specific bonuses
/// </summary>
/// <remarks>
/// On most systems this is equivalent to printf.
/// On Windows it works with utf-8 strings (like printf does on any other target)
/// and also prints to the debug console in IDEs.
/// On Android this uses the android logging functions and also passes the logging level.
/// </remarks>
/// <param name="log_level">
/// The logLevel is ignored on all targets but Android where it is converted
/// to the equivalent Android log level
/// </param>
/// <param name="format">The parameter is equivalent to the first printf parameter.</param>
/// <param name="...">The parameter is equivalent to the second printf parameter.</param>
KINC_FUNC void kinc_log(kinc_log_level_t log_level, const char *format, ...);
/// <summary>
/// Equivalent to kinc_log but uses a va_list parameter
/// </summary>
/// <remarks>
/// You will need this if you want to log parameters using va_start/va_end.
/// </remarks>
/// <param name="log_level">
/// The logLevel is ignored on all targets but Android where it is converted
/// to the equivalent Android log level
/// </param>
/// <param name="format">The parameter is equivalent to the first vprintf parameter.</param>
/// <param name="args">The parameter is equivalent to the second vprintf parameter.</param>
KINC_FUNC void kinc_log_args(kinc_log_level_t log_level, const char *format, va_list args);
#ifdef KINC_IMPLEMENTATION_ROOT
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <stdio.h>
#include <string.h>
#ifdef KINC_IMPLEMENTATION_ROOT
#undef KINC_IMPLEMENTATION
#endif
#ifdef KINC_MICROSOFT
#include <kinc/backend/MiniWindows.h>
#include <kinc/backend/SystemMicrosoft.h>
#endif
#ifdef KINC_ANDROID
#include <android/log.h>
#endif
void kinc_log(kinc_log_level_t level, const char *format, ...) {
va_list args;
va_start(args, format);
kinc_log_args(level, format, args);
va_end(args);
}
#define UTF8
void kinc_log_args(kinc_log_level_t level, const char *format, va_list args) {
#ifdef KINC_MICROSOFT
#ifdef UTF8
wchar_t buffer[4096];
kinc_microsoft_format(format, args, buffer);
wcscat(buffer, L"\r\n");
OutputDebugStringW(buffer);
#ifdef KINC_WINDOWS
DWORD written;
WriteConsoleW(GetStdHandle(level == KINC_LOG_LEVEL_INFO ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), buffer, (DWORD)wcslen(buffer), &written, NULL);
#endif
#else
char buffer[4096];
vsnprintf(buffer, 4090, format, args);
strcat(buffer, "\r\n");
OutputDebugStringA(buffer);
#ifdef KINC_WINDOWS
DWORD written;
WriteConsoleA(GetStdHandle(level == KINC_LOG_LEVEL_INFO ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), buffer, (DWORD)strlen(buffer), &written, NULL);
#endif
#endif
#else
char buffer[4096];
vsnprintf(buffer, 4090, format, args);
strcat(buffer, "\n");
fprintf(level == KINC_LOG_LEVEL_INFO ? stdout : stderr, "%s", buffer);
#endif
#ifdef KINC_ANDROID
switch (level) {
case KINC_LOG_LEVEL_INFO:
__android_log_vprint(ANDROID_LOG_INFO, "Kinc", format, args);
break;
case KINC_LOG_LEVEL_WARNING:
__android_log_vprint(ANDROID_LOG_WARN, "Kinc", format, args);
break;
case KINC_LOG_LEVEL_ERROR:
__android_log_vprint(ANDROID_LOG_ERROR, "Kinc", format, args);
break;
}
#endif
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,70 @@
#pragma once
#include <kinc/global.h>
/*! \file core.h
\brief Just a few very simple additions to math.h
the C-lib.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_PI 3.141592654
#define KINC_TAU 6.283185307
KINC_FUNC float kinc_cot(float x);
KINC_FUNC float kinc_round(float value);
KINC_FUNC float kinc_abs(float value);
KINC_FUNC float kinc_min(float a, float b);
KINC_FUNC float kinc_max(float a, float b);
KINC_FUNC int kinc_mini(int a, int b);
KINC_FUNC int kinc_maxi(int a, int b);
KINC_FUNC float kinc_clamp(float value, float minValue, float maxValue);
#ifdef KINC_IMPLEMENTATION_MATH
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <math.h>
float kinc_cot(float x) {
return cosf(x) / sinf(x);
}
float kinc_round(float value) {
return floorf(value + 0.5f);
}
float kinc_abs(float value) {
return value < 0 ? -value : value;
}
float kinc_min(float a, float b) {
return a > b ? b : a;
}
float kinc_max(float a, float b) {
return a > b ? a : b;
}
int kinc_mini(int a, int b) {
return a > b ? b : a;
}
int kinc_maxi(int a, int b) {
return a > b ? a : b;
}
float kinc_clamp(float value, float minValue, float maxValue) {
return kinc_max(minValue, kinc_min(maxValue, value));
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,5 @@
#define KINC_IMPLEMENTATION_MATH
#include "core.h"
#include "matrix.h"
#include "random.h"

View File

@ -0,0 +1,198 @@
#pragma once
#include "vector.h"
/*! \file matrix.h
\brief Provides basic matrix types and a few functions which create transformation-matrices. This only provides functionality which is needed elsewhere in
Kinc - if you need more, look up how transformation-matrices work and add some functions to your own project. Alternatively the Kore/C++-API also provides a
more complete matrix-API.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_matrix3x3 {
float m[3 * 3];
} kinc_matrix3x3_t;
KINC_FUNC float kinc_matrix3x3_get(kinc_matrix3x3_t *matrix, int x, int y);
KINC_FUNC void kinc_matrix3x3_set(kinc_matrix3x3_t *matrix, int x, int y, float value);
KINC_FUNC void kinc_matrix3x3_transpose(kinc_matrix3x3_t *matrix);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_identity(void);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_rotation_x(float alpha);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_rotation_y(float alpha);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_rotation_z(float alpha);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_translation(float x, float y);
KINC_FUNC kinc_matrix3x3_t kinc_matrix3x3_multiply(kinc_matrix3x3_t *a, kinc_matrix3x3_t *b);
KINC_FUNC kinc_vector3_t kinc_matrix3x3_multiply_vector(kinc_matrix3x3_t *a, kinc_vector3_t b);
typedef struct kinc_matrix4x4 {
float m[4 * 4];
} kinc_matrix4x4_t;
KINC_FUNC float kinc_matrix4x4_get(kinc_matrix4x4_t *matrix, int x, int y);
KINC_FUNC void kinc_matrix4x4_set(kinc_matrix4x4_t *matrix, int x, int y, float value);
KINC_FUNC void kinc_matrix4x4_transpose(kinc_matrix4x4_t *matrix);
KINC_FUNC kinc_matrix4x4_t kinc_matrix4x4_multiply(kinc_matrix4x4_t *a, kinc_matrix4x4_t *b);
#ifdef KINC_IMPLEMENTATION_MATH
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#ifdef KINC_IMPLEMENTATION_MATH
#undef KINC_IMPLEMENTATION
#endif
#include <kinc/math/core.h>
#include <kinc/math/matrix.h>
#ifdef KINC_IMPLEMENTATION_MATH
#define KINC_IMPLEMENTATION
#endif
#include <string.h>
float kinc_matrix3x3_get(kinc_matrix3x3_t *matrix, int x, int y) {
return matrix->m[x * 3 + y];
}
void kinc_matrix3x3_set(kinc_matrix3x3_t *matrix, int x, int y, float value) {
matrix->m[x * 3 + y] = value;
}
void kinc_matrix3x3_transpose(kinc_matrix3x3_t *matrix) {
kinc_matrix3x3_t transposed;
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
kinc_matrix3x3_set(&transposed, x, y, kinc_matrix3x3_get(matrix, y, x));
}
}
memcpy(matrix->m, transposed.m, sizeof(transposed.m));
}
kinc_matrix3x3_t kinc_matrix3x3_identity(void) {
kinc_matrix3x3_t m;
memset(m.m, 0, sizeof(m.m));
for (unsigned x = 0; x < 3; ++x) {
kinc_matrix3x3_set(&m, x, x, 1.0f);
}
return m;
}
kinc_matrix3x3_t kinc_matrix3x3_rotation_x(float alpha) {
kinc_matrix3x3_t m = kinc_matrix3x3_identity();
float ca = cosf(alpha);
float sa = sinf(alpha);
kinc_matrix3x3_set(&m, 1, 1, ca);
kinc_matrix3x3_set(&m, 2, 1, -sa);
kinc_matrix3x3_set(&m, 1, 2, sa);
kinc_matrix3x3_set(&m, 2, 2, ca);
return m;
}
kinc_matrix3x3_t kinc_matrix3x3_rotation_y(float alpha) {
kinc_matrix3x3_t m = kinc_matrix3x3_identity();
float ca = cosf(alpha);
float sa = sinf(alpha);
kinc_matrix3x3_set(&m, 0, 0, ca);
kinc_matrix3x3_set(&m, 2, 0, sa);
kinc_matrix3x3_set(&m, 0, 2, -sa);
kinc_matrix3x3_set(&m, 2, 2, ca);
return m;
}
kinc_matrix3x3_t kinc_matrix3x3_rotation_z(float alpha) {
kinc_matrix3x3_t m = kinc_matrix3x3_identity();
float ca = cosf(alpha);
float sa = sinf(alpha);
kinc_matrix3x3_set(&m, 0, 0, ca);
kinc_matrix3x3_set(&m, 1, 0, -sa);
kinc_matrix3x3_set(&m, 0, 1, sa);
kinc_matrix3x3_set(&m, 1, 1, ca);
return m;
}
kinc_matrix3x3_t kinc_matrix3x3_translation(float x, float y) {
kinc_matrix3x3_t m = kinc_matrix3x3_identity();
kinc_matrix3x3_set(&m, 2, 0, x);
kinc_matrix3x3_set(&m, 2, 1, y);
return m;
}
#ifdef __clang__
#pragma clang diagnostic ignored "-Wconditional-uninitialized"
#endif
kinc_matrix3x3_t kinc_matrix3x3_multiply(kinc_matrix3x3_t *a, kinc_matrix3x3_t *b) {
kinc_matrix3x3_t result;
for (unsigned x = 0; x < 3; ++x) {
for (unsigned y = 0; y < 3; ++y) {
float t = kinc_matrix3x3_get(a, 0, y) * kinc_matrix3x3_get(b, x, 0);
for (unsigned i = 1; i < 3; ++i) {
t += kinc_matrix3x3_get(a, i, y) * kinc_matrix3x3_get(b, x, i);
}
kinc_matrix3x3_set(&result, x, y, t);
}
}
return result;
}
static float vector3_get(kinc_vector3_t vec, int index) {
float *values = (float *)&vec;
return values[index];
}
static void vector3_set(kinc_vector3_t *vec, int index, float value) {
float *values = (float *)vec;
values[index] = value;
}
kinc_vector3_t kinc_matrix3x3_multiply_vector(kinc_matrix3x3_t *a, kinc_vector3_t b) {
kinc_vector3_t product;
for (unsigned y = 0; y < 3; ++y) {
float t = 0;
for (unsigned x = 0; x < 3; ++x) {
t += kinc_matrix3x3_get(a, x, y) * vector3_get(b, x);
}
vector3_set(&product, y, t);
}
return product;
}
float kinc_matrix4x4_get(kinc_matrix4x4_t *matrix, int x, int y) {
return matrix->m[x * 4 + y];
}
void kinc_matrix4x4_set(kinc_matrix4x4_t *matrix, int x, int y, float value) {
matrix->m[x * 4 + y] = value;
}
void kinc_matrix4x4_transpose(kinc_matrix4x4_t *matrix) {
kinc_matrix4x4_t transposed;
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
kinc_matrix4x4_set(&transposed, x, y, kinc_matrix4x4_get(matrix, y, x));
}
}
memcpy(matrix->m, transposed.m, sizeof(transposed.m));
}
kinc_matrix4x4_t kinc_matrix4x4_multiply(kinc_matrix4x4_t *a, kinc_matrix4x4_t *b) {
kinc_matrix4x4_t result;
for (unsigned x = 0; x < 4; ++x)
for (unsigned y = 0; y < 4; ++y) {
float t = kinc_matrix4x4_get(a, 0, y) * kinc_matrix4x4_get(b, x, 0);
for (unsigned i = 1; i < 4; ++i) {
t += kinc_matrix4x4_get(a, i, y) * kinc_matrix4x4_get(b, x, i);
}
kinc_matrix4x4_set(&result, x, y, t);
}
return result;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,22 @@
#pragma once
#include "core.h"
/*! \file quaternion.h
\brief Provides a basic quaternion type.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_quaternion {
float x;
float y;
float z;
float w;
} kinc_quaternion_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,98 @@
#pragma once
#include <kinc/global.h>
/*! \file random.h
\brief Generates values which are kind of random.
*/
#ifdef __cplusplus
extern "C" {
#endif
/// <summary>
/// Initializes the randomizer with a seed. This is optional but helpful.
/// </summary>
/// <param name="seed">A value which should ideally be pretty random</param>
KINC_FUNC void kinc_random_init(int64_t seed);
/// <summary>
/// Returns a random value.
/// </summary>
/// <returns>A random value</returns>
KINC_FUNC int64_t kinc_random_get(void);
/// <summary>
/// Returns a value between 0 and max (both inclusive).
/// </summary>
/// <returns>A random value</returns>
KINC_FUNC int64_t kinc_random_get_max(int64_t max);
/// <summary>
/// Returns a value between min and max (both inclusive).
/// </summary>
/// <returns>A random value</returns>
KINC_FUNC int64_t kinc_random_get_in(int64_t min, int64_t max);
#ifdef KINC_IMPLEMENTATION_MATH
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#include <limits.h>
#include <stdlib.h>
// xoshiro256** 1.0
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
static uint64_t s[4] = {1, 2, 3, 4};
uint64_t next(void) {
const uint64_t result = rotl(s[1] * 5, 7) * 9;
const uint64_t t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
return result;
}
void kinc_random_init(int64_t seed) {
s[0] = (uint64_t)seed;
s[1] = 2;
s[2] = 3;
s[3] = 4;
s[1] = next();
s[2] = next();
s[3] = next();
}
int64_t kinc_random_get(void) {
return (int64_t)next();
}
int64_t kinc_random_get_max(int64_t max) {
return kinc_random_get() % (max + 1);
}
int64_t kinc_random_get_in(int64_t min, int64_t max) {
int64_t value = kinc_random_get();
return (value < -LLONG_MAX ? LLONG_MAX : llabs(value)) % (max + 1 - min) + min;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,33 @@
#pragma once
#include "core.h"
/*! \file vector.h
\brief Provides basic vector types.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef struct kinc_vector2 {
float x;
float y;
} kinc_vector2_t;
typedef struct kinc_vector3 {
float x;
float y;
float z;
} kinc_vector3_t;
typedef struct kinc_vector4 {
float x;
float y;
float z;
float w;
} kinc_vector4_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,49 @@
#pragma once
#include <kinc/global.h>
#include <stdbool.h>
/*! \file http.h
\brief Provides a simple http-API.
*/
#ifdef __cplusplus
extern "C" {
#endif
#define KINC_HTTP_GET 0
#define KINC_HTTP_POST 1
#define KINC_HTTP_PUT 2
#define KINC_HTTP_DELETE 3
typedef void (*kinc_http_callback_t)(int error, int response, const char *body, void *callbackdata);
/// <summary>
/// Fires off an http request.
/// </summary>
KINC_FUNC void kinc_http_request(const char *url, const char *path, const char *data, int port, bool secure, int method, const char *header,
kinc_http_callback_t callback, void *callbackdata);
#ifdef KINC_IMPLEMENTATION_NETWORK
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#if !defined KINC_MACOS && !defined KINC_IOS && !defined KINC_WINDOWS
#include <assert.h>
void kinc_http_request(const char *url, const char *path, const char *data, int port, bool secure, int method, const char *header,
kinc_http_callback_t callback, void *callbackdata) {
assert(false); // not implemented for the current system, please send a pull-request
}
#endif
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,4 @@
#define KINC_IMPLEMENTATION_NETWORK
#include "http.h"
#include "socket.h"

View File

@ -0,0 +1,665 @@
#pragma once
#include <kinc/global.h>
/*! \file socket.h
\brief Provides low-level network-communication via UDP or TCP-sockets.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum kinc_socket_protocol { KINC_SOCKET_PROTOCOL_UDP, KINC_SOCKET_PROTOCOL_TCP } kinc_socket_protocol_t;
typedef enum kinc_socket_family { KINC_SOCKET_FAMILY_IP4, KINC_SOCKET_FAMILY_IP6 } kinc_socket_family_t;
#ifdef KINC_MICROSOFT
#if defined(_WIN64)
typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
#else
#if !defined _W64
#define _W64
#endif
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
#endif
typedef UINT_PTR SOCKET;
#endif
typedef struct kinc_socket {
#ifdef KINC_MICROSOFT
SOCKET handle;
#else
int handle;
#endif
uint32_t host;
uint32_t port;
kinc_socket_protocol_t protocol;
kinc_socket_family_t family;
bool connected;
} kinc_socket_t;
typedef struct kinc_socket_options {
bool non_blocking;
bool broadcast;
bool tcp_no_delay;
} kinc_socket_options_t;
/// <summary>
/// Initializes a socket-options-object to the default options
/// </summary>
/// <param name="options">The new default options</param>
KINC_FUNC void kinc_socket_options_set_defaults(kinc_socket_options_t *options);
/// <summary>
/// Initializes a socket-object. To set the host and port use kinc_socket_set.
/// Host will be localhost
/// Port will be 8080
/// Family will be IPv4
/// Protocol will be TCP
/// </summary>
/// <param name="socket">The socket to initialize</param>
KINC_FUNC void kinc_socket_init(kinc_socket_t *socket);
/// <summary>
/// Sets the sockets properties.
/// </summary>
/// <param name="socket">The socket-object to use</param>
/// <param name="host">The host to use as IP or URL</param>
/// <param name="port">The port to use</param>
/// <param name="family">The IP-family to use</param>
/// <param name="protocol">The protocol to use</param>
/// <returns>Whether the socket was set correctly</returns>
KINC_FUNC bool kinc_socket_set(kinc_socket_t *socket, const char *host, int port, kinc_socket_family_t family, kinc_socket_protocol_t protocol);
/// <summary>
/// Destroys a socket-object.
/// </summary>
/// <param name="socket">The socket to destroy</param>
KINC_FUNC void kinc_socket_destroy(kinc_socket_t *socket);
/// <summary>
/// Opens a socket-connection.
/// </summary>
/// <param name="socket">The socket-object to use</param>
/// <param name="protocol">The protocol to use</param>
/// <param name="port">The port to use</param>
/// <param name="options">The options to use</param>
/// <returns>Whether the socket-connection could be opened</returns>
KINC_FUNC bool kinc_socket_open(kinc_socket_t *socket, kinc_socket_options_t *options);
/// <summary>
/// For use with non-blocking sockets to try to see if we are connected.
/// </summary>
/// <param name="socket">The socket-object to use</param>
/// <param name="waittime">The amount of time in seconds the select function will timeout.</param>
/// <param name="read">Check if the socket is ready to be read from.</param>
/// <param name="write">Check if the socket is ready to be written to.</param>
/// <returns>Whether the socket-connection can read or write or checks both.</returns>
KINC_FUNC bool kinc_socket_select(kinc_socket_t *socket, uint32_t waittime, bool read, bool write);
/*Typically these are server actions.*/
KINC_FUNC bool kinc_socket_bind(kinc_socket_t *socket);
KINC_FUNC bool kinc_socket_listen(kinc_socket_t *socket, int backlog);
KINC_FUNC bool kinc_socket_accept(kinc_socket_t *socket, kinc_socket_t *new_socket, unsigned *remote_address, unsigned *remote_port);
/*Typically this is a client action.*/
KINC_FUNC bool kinc_socket_connect(kinc_socket_t *socket);
KINC_FUNC int kinc_socket_send(kinc_socket_t *socket, const uint8_t *data, int size);
KINC_FUNC int kinc_socket_send_address(kinc_socket_t *socket, unsigned address, int port, const uint8_t *data, int size);
KINC_FUNC int kinc_socket_send_url(kinc_socket_t *socket, const char *url, int port, const uint8_t *data, int size);
KINC_FUNC int kinc_socket_receive(kinc_socket_t *socket, uint8_t *data, int maxSize, unsigned *from_address, unsigned *from_port);
/// <summary>
/// Resolves a DNS-entry to an IP and returns its integer representation.
/// </summary>
/// <param name="url"></param>
/// <param name="port"></param>
/// <returns></returns>
KINC_FUNC unsigned kinc_url_to_int(const char *url, int port);
#ifdef KINC_IMPLEMENTATION_NETWORK
#define KINC_IMPLEMENTATION
#endif
#ifdef KINC_IMPLEMENTATION
#undef KINC_IMPLEMENTATION
#include <kinc/libs/stb_sprintf.h>
#include <kinc/log.h>
#define KINC_IMPLEMENTATION
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
// Windows 7
#define WINVER 0x0601
#define _WIN32_WINNT 0x0601
#define NOATOM
#define NOCLIPBOARD
#define NOCOLOR
#define NOCOMM
#define NOCTLMGR
#define NODEFERWINDOWPOS
#define NODRAWTEXT
#define NOGDI
#define NOGDICAPMASKS
#define NOHELP
#define NOICONS
#define NOKANJI
#define NOKEYSTATES
#define NOMB
#define NOMCX
#define NOMEMMGR
#define NOMENUS
#define NOMETAFILE
#define NOMINMAX
#define NOMSG
#define NONLS
#define NOOPENFILE
#define NOPROFILER
#define NORASTEROPS
#define NOSCROLL
#define NOSERVICE
#define NOSHOWWINDOW
#define NOSOUND
#define NOSYSCOMMANDS
#define NOSYSMETRICS
#define NOTEXTMETRIC
#define NOUSER
#define NOVIRTUALKEYCODES
#define NOWH
#define NOWINMESSAGES
#define NOWINOFFSETS
#define NOWINSTYLES
#define WIN32_LEAN_AND_MEAN
#include <Ws2tcpip.h>
#include <winsock2.h>
#elif defined(KINC_POSIX) || defined(KINC_EMSCRIPTEN)
#include <arpa/inet.h> // for inet_addr()
#include <ctype.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#if defined(KINC_EMSCRIPTEN)
#include <emscripten.h>
#include <emscripten/posix_socket.h>
#include <emscripten/threading.h>
#include <emscripten/websocket.h>
static EMSCRIPTEN_WEBSOCKET_T bridgeSocket = 0;
#elif defined(KINC_POSIX)
#include <sys/select.h>
#endif
static int counter = 0;
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
// Important: Must be cleaned with freeaddrinfo(address) later if the result is 0 in order to prevent memory leaks
static int resolveAddress(const char *url, int port, struct addrinfo **result) {
struct addrinfo hints = {0};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
char serv[6];
sprintf(serv, "%u", port);
return getaddrinfo(url, serv, &hints, result);
}
#endif
KINC_FUNC bool kinc_socket_bind(kinc_socket_t *sock) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
struct sockaddr_in address;
address.sin_family = sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6;
address.sin_addr.s_addr = sock->host;
address.sin_port = sock->port;
if (bind(sock->handle, (const struct sockaddr *)&address, sizeof(struct sockaddr_in)) < 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not bind socket: %s", strerror(errno));
return false;
}
return true;
#else
return false;
#endif
}
KINC_FUNC void kinc_socket_options_set_defaults(kinc_socket_options_t *options) {
options->non_blocking = true;
options->broadcast = false;
options->tcp_no_delay = false;
}
void kinc_socket_init(kinc_socket_t *sock) {
sock->handle = 0;
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
sock->host = INADDR_ANY;
sock->port = htons((unsigned short)8080);
sock->protocol = KINC_SOCKET_PROTOCOL_TCP;
sock->family = KINC_SOCKET_FAMILY_IP4;
#endif
sock->connected = false;
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
if (counter == 0) {
WSADATA WsaData;
WSAStartup(MAKEWORD(2, 2), &WsaData);
}
#if defined(KINC_EMSCRIPTEN)
if (!bridgeSocket) {
bridgeSocket = emscripten_init_websocket_to_posix_socket_bridge("ws://localhost:8080");
// Synchronously wait until connection has been established.
uint16_t readyState = 0;
do {
emscripten_websocket_get_ready_state(bridgeSocket, &readyState);
emscripten_thread_sleep(100);
} while (readyState == 0);
}
#endif
#endif
++counter;
}
bool kinc_socket_open(kinc_socket_t *sock, struct kinc_socket_options *options) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
switch (sock->protocol) {
case KINC_SOCKET_PROTOCOL_UDP:
sock->handle = socket(sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
break;
case KINC_SOCKET_PROTOCOL_TCP:
sock->handle = socket(sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6, SOCK_STREAM, IPPROTO_TCP);
break;
default:
kinc_log(KINC_LOG_LEVEL_ERROR, "Unsupported socket protocol.");
return false;
}
if (sock->handle <= 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not create socket.");
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
int errorCode = WSAGetLastError();
switch (errorCode) {
case (WSANOTINITIALISED):
kinc_log(KINC_LOG_LEVEL_ERROR, "A successful WSAStartup call must occur before using this function.");
break;
case (WSAENETDOWN):
kinc_log(KINC_LOG_LEVEL_ERROR, "The network subsystem or the associated service provider has failed.");
break;
case (WSAEAFNOSUPPORT):
kinc_log(KINC_LOG_LEVEL_ERROR,
"The specified address family is not supported.For example, an application tried to create a socket for the AF_IRDA address "
"family but an infrared adapter and device driver is not installed on the local computer.");
break;
case (WSAEINPROGRESS):
kinc_log(KINC_LOG_LEVEL_ERROR,
"A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.");
break;
case (WSAEMFILE):
kinc_log(KINC_LOG_LEVEL_ERROR, "No more socket descriptors are available.");
break;
case (WSAEINVAL):
kinc_log(KINC_LOG_LEVEL_ERROR,
"An invalid argument was supplied.This error is returned if the af parameter is set to AF_UNSPEC and the type and protocol "
"parameter are unspecified.");
break;
case (WSAENOBUFS):
kinc_log(KINC_LOG_LEVEL_ERROR, "No buffer space is available.The socket cannot be created.");
break;
case (WSAEPROTONOSUPPORT):
kinc_log(KINC_LOG_LEVEL_ERROR, "The specified protocol is not supported.");
break;
case (WSAEPROTOTYPE):
kinc_log(KINC_LOG_LEVEL_ERROR, "The specified protocol is the wrong type for this socket.");
break;
case (WSAEPROVIDERFAILEDINIT):
kinc_log(KINC_LOG_LEVEL_ERROR,
"The service provider failed to initialize.This error is returned if a layered service provider(LSP) or namespace provider was "
"improperly installed or the provider fails to operate correctly.");
break;
case (WSAESOCKTNOSUPPORT):
kinc_log(KINC_LOG_LEVEL_ERROR, "The specified socket type is not supported in this address family.");
break;
case (WSAEINVALIDPROVIDER):
kinc_log(KINC_LOG_LEVEL_ERROR, "The service provider returned a version other than 2.2.");
break;
case (WSAEINVALIDPROCTABLE):
kinc_log(KINC_LOG_LEVEL_ERROR, "The service provider returned an invalid or incomplete procedure table to the WSPStartup.");
break;
default:
kinc_log(KINC_LOG_LEVEL_ERROR, "Unknown error.");
}
#elif defined(KINC_POSIX) && !defined(KINC_EMSCRIPTEN)
kinc_log(KINC_LOG_LEVEL_ERROR, "%s", strerror(errno));
#endif
return false;
}
#endif
if (options) {
if (options->non_blocking) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
DWORD value = 1;
if (ioctlsocket(sock->handle, FIONBIO, &value) != 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not set non-blocking mode.");
return false;
}
#elif defined(KINC_POSIX)
int value = 1;
if (fcntl(sock->handle, F_SETFL, O_NONBLOCK, value) == -1) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not set non-blocking mode.");
return false;
}
#endif
}
if (options->broadcast) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
int value = 1;
if (setsockopt(sock->handle, SOL_SOCKET, SO_BROADCAST, (const char *)&value, sizeof(value)) < 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not set broadcast mode.");
return false;
}
#endif
}
if (options->tcp_no_delay) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
int value = 1;
if (setsockopt(sock->handle, IPPROTO_TCP, TCP_NODELAY, (const char *)&value, sizeof(value)) != 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not set no-delay mode.");
return false;
}
#endif
}
}
return true;
}
void kinc_socket_destroy(kinc_socket_t *sock) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
closesocket(sock->handle);
#elif defined(KINC_POSIX)
close(sock->handle);
#endif
memset(sock, 0, sizeof(kinc_socket_t));
--counter;
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
if (counter == 0) {
WSACleanup();
}
#endif
}
bool kinc_socket_select(kinc_socket_t *sock, uint32_t waittime, bool read, bool write) {
#if !defined(KINC_EMSCRIPTEN) && (defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX))
fd_set r_fds, w_fds;
struct timeval timeout;
FD_ZERO(&r_fds);
FD_ZERO(&w_fds);
FD_SET(sock->handle, &r_fds);
FD_SET(sock->handle, &w_fds);
timeout.tv_sec = waittime;
timeout.tv_usec = 0;
if (select(0, &r_fds, &w_fds, NULL, &timeout) < 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "kinc_socket_select didn't work: %s", strerror(errno));
return false;
}
if (read && write) {
return FD_ISSET(sock->handle, &w_fds) && FD_ISSET(sock->handle, &r_fds);
}
else if (read) {
return FD_ISSET(sock->handle, &r_fds);
}
else if (write) {
return FD_ISSET(sock->handle, &w_fds);
}
else {
kinc_log(KINC_LOG_LEVEL_ERROR, "Calling kinc_socket_select with both read and write set to false is useless.");
return false;
}
#else
return false;
#endif
}
bool kinc_socket_set(kinc_socket_t *sock, const char *host, int port, kinc_socket_family_t family, kinc_socket_protocol_t protocol) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
sock->family = family;
sock->protocol = protocol;
sock->port = htons((unsigned short)port);
if (host == NULL)
return true;
if (isdigit(host[0]) || (family == KINC_SOCKET_FAMILY_IP6 && host[4] == ':')) { // Is IPv4 or IPv6 string
struct in_addr addr;
if (inet_pton(sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6, host, &addr) == 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Invalid %s address: %s\n", sock->family == KINC_SOCKET_FAMILY_IP4 ? "IPv4" : "IPv6", host);
return false;
}
sock->host = addr.s_addr;
return true;
}
else {
struct addrinfo *address = NULL;
int res = resolveAddress(host, port, &address);
if (res != 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not resolve address.");
return false;
}
#if defined(KINC_POSIX)
sock->host = ((struct sockaddr_in *)address->ai_addr)->sin_addr.s_addr;
#else
sock->host = ((struct sockaddr_in *)address->ai_addr)->sin_addr.S_un.S_addr;
#endif
freeaddrinfo(address);
return true;
}
#else
return false;
#endif
}
bool kinc_socket_listen(kinc_socket_t *socket, int backlog) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
int res = listen(socket->handle, backlog);
return (res == 0);
#else
return false;
#endif
}
bool kinc_socket_accept(kinc_socket_t *sock, kinc_socket_t *newSocket, unsigned *remoteAddress, unsigned *remotePort) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
typedef int socklen_t;
#endif
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
struct sockaddr_in addr;
socklen_t addrLength = sizeof(addr);
newSocket->handle = accept(sock->handle, (struct sockaddr *)&addr, &addrLength);
if (newSocket->handle <= 0) {
return false;
}
newSocket->connected = sock->connected = true;
newSocket->host = addr.sin_addr.s_addr;
newSocket->port = addr.sin_port;
newSocket->family = sock->family;
newSocket->protocol = sock->protocol;
*remoteAddress = ntohl(addr.sin_addr.s_addr);
*remotePort = ntohs(addr.sin_port);
return true;
#else
return false;
#endif
}
bool kinc_socket_connect(kinc_socket_t *sock) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
struct sockaddr_in addr;
addr.sin_family = sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6;
addr.sin_addr.s_addr = sock->host;
addr.sin_port = sock->port;
int res = connect(sock->handle, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
return sock->connected = (res == 0);
#else
return false;
#endif
}
int kinc_socket_send(kinc_socket_t *sock, const uint8_t *data, int size) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
typedef int socklen_t;
#endif
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
if (sock->protocol == KINC_SOCKET_PROTOCOL_UDP) {
struct sockaddr_in addr;
addr.sin_family = sock->family == KINC_SOCKET_FAMILY_IP4 ? AF_INET : AF_INET6;
addr.sin_addr.s_addr = sock->host;
addr.sin_port = sock->port;
size_t sent = sendto(sock->handle, (const char *)data, size, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (sent != size) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not send packet.");
return -1;
}
return (int)sent;
}
else {
if (!sock->connected) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Call kinc_sockect_connect/bind before send/recv can be called for TCP sockets.");
return -1;
}
size_t sent = send(sock->handle, (const char *)data, size, 0);
if (sent != size) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not send packet.");
}
return (int)sent;
}
#else
return 0;
#endif
}
int kinc_socket_send_address(kinc_socket_t *sock, unsigned address, int port, const uint8_t *data, int size) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address);
addr.sin_port = htons(port);
size_t sent = sendto(sock->handle, (const char *)data, size, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (sent != size) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not send packet.");
}
return (int)sent;
#else
return 0;
#endif
}
int kinc_socket_send_url(kinc_socket_t *sock, const char *url, int port, const uint8_t *data, int size) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
struct addrinfo *address = NULL;
int res = resolveAddress(url, port, &address);
if (res != 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not resolve address.");
return 0;
}
size_t sent = sendto(sock->handle, (const char *)data, size, 0, address->ai_addr, sizeof(struct sockaddr_in));
if (sent != size) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not send packet.");
}
freeaddrinfo(address);
return (int)sent;
#else
return 0;
#endif
}
int kinc_socket_receive(kinc_socket_t *sock, uint8_t *data, int maxSize, unsigned *fromAddress, unsigned *fromPort) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
typedef int socklen_t;
typedef int ssize_t;
#endif
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP) || defined(KINC_POSIX)
if (sock->protocol == KINC_SOCKET_PROTOCOL_UDP) {
struct sockaddr_in from;
socklen_t fromLength = sizeof(from);
ssize_t bytes = recvfrom(sock->handle, (char *)data, maxSize, 0, (struct sockaddr *)&from, &fromLength);
if (bytes <= 0) {
return (int)bytes;
}
*fromAddress = ntohl(from.sin_addr.s_addr);
*fromPort = ntohs(from.sin_port);
return (int)bytes;
}
else {
if (!sock->connected) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Call kinc_sockect_connect/bind before send/recv can be called for TCP sockets.");
return -1;
}
ssize_t bytes = recv(sock->handle, (char *)data, maxSize, 0);
*fromAddress = ntohl(sock->host);
*fromPort = ntohs(sock->port);
return (int)bytes;
}
#else
return 0;
#endif
}
unsigned kinc_url_to_int(const char *url, int port) {
#if defined(KINC_WINDOWS) || defined(KINC_WINDOWSAPP)
struct addrinfo *address = NULL;
int res = resolveAddress(url, port, &address);
if (res != 0) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Could not resolve address.");
return -1;
}
unsigned fromAddress = ntohl(((struct sockaddr_in *)address->ai_addr)->sin_addr.S_un.S_addr);
freeaddrinfo(address);
return fromAddress;
#else
return 0;
#endif
}
#endif
#ifdef __cplusplus
}
#endif

Some files were not shown because too many files have changed in this diff Show More