summaryrefslogtreecommitdiff
path: root/src/core/texture.c
blob: 33a00c57732e7c36f6fd079a61e9778f4e077970 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "texture.h"
#define STB_IMAGE_IMPLEMENTATION
#include "../extern/stb_image.h"
#include <stdio.h>

static void texture_abgr2argb(Texture* tex) {
	ssr_assert(tex);
	int width = tex->width, height = tex->height;
	Color* pixels = tex->pixels;
	for (int i = 0; i < width * height; ++i) {
		uint r = (pixels[i] & 0xff) << 16;
		uint g = ((pixels[i] >> 8) & 0xff) << 8;
		uint b = ((pixels[i] >> 16) & 0xff);
		uint a = ((pixels[i] >> 24) & 0xff) << 24;
		pixels[i] = r | g | b | a;
	}
}

static void texture_abgr2c32(Color* abgr, Color32* color, int count) {
	for (int i = 0; i < count; ++i) {
		color[i].r = (abgr[i] & 0xff) / 255.f;
		color[i].g = ((abgr[i] >> 8) & 0xff) / 255.f;
		color[i].b = ((abgr[i] >> 16) & 0xff) / 255.f;
		color[i].a = ((abgr[i] >> 24) & 0xff) / 255.f;
	}
}

Texture* texture_loadfromfile(const char* path) {
	ssr_assert(path);
	FILE* file = fopen(path, "rb");
	ssr_assert(file);
	fseek(file, 0, SEEK_END);
	int size = ftell(file);
	fseek(file, 0, SEEK_SET);
	char* buffer = ssrM_newvector(char, size);
	ssr_assert(buffer);
	int l = fread(buffer, 1, size, file);
	if ( l!= size) {
		free(buffer);
		fclose(file);
		return NULL;
	}
	fclose(file);
	int width, height;
	Color* pixels = (Color*)stbi_load_from_memory((unsigned char*)buffer, size, &width, &height, NULL, STBI_rgb_alpha);
	ssrM_free(buffer);
	if (!pixels) return NULL;
	Texture* texture = ssrM_new(Texture);
	texture->width = width; texture->height = height;
	texture->pixels = ssrM_newvector(Color32, width*height);
	texture->filter_mode = FILTERMODE_POINT;
	texture->wrap_mode = WRAPMODE_CLAMP;
	texture_abgr2c32(pixels, texture->pixels, width*height);
	ssrM_free(pixels);
	return texture;
}

Texture* texture_create(uint width, uint height) {
	Texture* tex = ssrM_new(Texture);
	tex->pixels = ssrM_newvector(Color32, width*height);
	tex->width = width;
	tex->height = height;
	tex->filter_mode = FILTERMODE_POINT;
	tex->wrap_mode = WRAPMODE_CLAMP;
	return  tex;
}

static Color32 sampling(Texture* tex, WrapMode wrap_mode, int x, int y) {
	if (wrap_mode == WRAPMODE_CLAMP) { /*clamp*/
		x = clamp(x, 0, tex->width - 1);
		y = clamp(y, 0, tex->height - 1);
	}	else { /*repeat*/
		x = x % tex->width; 
		y = y % tex->height;
	}
	return tex->pixels[x + y * tex->width];
}

Color32 texture_sampling(Texture* tex, float x01, float y01) {
	ssr_assert(tex);
	FilterMode filter_mode = tex->filter_mode;
	WrapMode wrap_mode = tex->wrap_mode;
	float x = x01 * tex->width, y = (1 - y01) * tex->height; /*map to texture coordinate*/
	int x_min = floor(x), y_min = floor(y);
	int x_max = ceil(x), y_max = ceil(y);
	if (filter_mode == FILTERMODE_POINT) {
		int px = (x_max - x > x - x_min) ? x_min : x_max;
		int py = (y_max - y > y - y_min) ? y_min : y_max;

		return sampling(tex, wrap_mode, px, py);
	}
	else if (filter_mode == FILTERMODE_BILINEAR) {
		static Color32 tl, tr, bl, br, t, b, out;

		tl = sampling(tex, wrap_mode, x_min, y_min);
		tr = sampling(tex, wrap_mode, x_max, y_min);
		bl = sampling(tex, wrap_mode, x_min, y_max);
		br = sampling(tex, wrap_mode, x_max, y_max);

		vec4_lerp(&tl, &tr, x - x_min, &t);
		vec4_lerp(&bl, &br, x - x_min, &b);
		vec4_lerp(&t, &b, y - y_min, &out);

		return out;
	}
	/*
	else if (filter_mode == FILTERMODE_TRILINEAR) {
	}
	*/
}

void texture_setfiltermode(Texture* tex, FilterMode filter) {
	ssr_assert(tex);
	tex->filter_mode = filter;
}

void texture_setwrapmode(Texture* tex, WrapMode wrap) {
	ssr_assert(tex);
	tex->wrap_mode = wrap;
}

void texture_free(Texture* tex) {
	if (tex->pixels) 
		ssrM_free(tex->pixels);
	ssrM_free(tex);
}