1 /*
2  *  fx/Texture.cpp
3  *
4  *  Copyright 2009 Peter Barth
5  *
6  *  This file is part of Milkytracker.
7  *
8  *  Milkytracker is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Milkytracker is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include "BasicTypes.h"
24 #include "Math3d.h"
25 #include "Texture.h"
26 #include "TCBSpline.h"
27 
28 #define RGB2SHORT(r,g,b) ((((r>>3))<<11)+(((g>>2))<<5)+((b>>3)))
29 
30 #define MAX_KEYS 50
31 #define MAX_TIME 200
32 
setPixel(int * buffer,int x,int y,int r,int g,int b)33 static void setPixel(int* buffer,int x,int y,int r,int g,int b)
34 {
35 	int offset = (y&255)*256+(x&255);
36 
37 	r+=buffer[offset*3]; if (r>65536) r = 65536;
38 	g+=buffer[offset*3+1]; if (g>65536) g = 65536;
39 	b+=buffer[offset*3+2]; if (b>65536) b = 65536;
40 
41 	buffer[offset*3] = r;
42 	buffer[offset*3+1] = g;
43 	buffer[offset*3+2] = b;
44 }
45 
setBlock(int * buffer,int x,int y,int blockSize,int r,int g,int b)46 static void setBlock(int* buffer,int x,int y,int blockSize, int r,int g,int b)
47 {
48 	for (int i = y; i < y+blockSize; i++)
49 		for (int j = x; j < x+blockSize; j++)
50 			setPixel(buffer, j, i, r,g,b);
51 }
52 
drawSplines(TCBSpline * spline,int maxDots,int maxTime,int * buffer,int blockSize,int r,int g,int b)53 static void drawSplines(TCBSpline* spline, int maxDots, int maxTime, int* buffer, int blockSize, int r, int g, int b)
54 {
55 
56 	float rMaxdots = (1.0f / (float)maxDots) * maxTime;
57 
58 	for (int j = 0; j < maxDots; j++)
59 	{
60 
61 		float curTime = (float)j * rMaxdots;
62 
63 		VectorFloat pos = spline->getPos(curTime);
64 
65 		//int shade = pos.z*65536.0f;
66 
67 		setBlock(buffer, (int)pos.x, (int)pos.y, blockSize, r, g, b);
68 
69 	}
70 }
71 
72 
createSplineTexture(unsigned char * tex,int numBlocks,int blockSize)73 void Texture::createSplineTexture(unsigned char* tex, int numBlocks, int blockSize)
74 {
75 
76 	TCBSpline* spline = new TCBSpline(MAX_KEYS);
77 
78 	int* buffer = new int[256*256*3];
79 
80 	memset(buffer, 0, 256*256*3*sizeof(int));
81 
82 	int i;
83 
84 	for (i = 0; i < MAX_KEYS; i++)
85 	{
86 		int x = rand()%256;
87 		int y = rand()%256;
88 
89 		int z = rand()%256;
90 
91 		VectorFloat v((float)x, (float)y, (float)z/255.0f);
92 
93 		spline->setKey(i, v, (int)(((1.0f/((float)MAX_KEYS-1.0f))*(float)i)*MAX_TIME));
94 	}
95 
96 	drawSplines(spline, numBlocks, MAX_TIME, buffer, blockSize, (5*65536/255)>>1, (4*65536/255)>>1, (65536*2/255)>>1);
97 
98 	for (i = 0; i < MAX_KEYS; i++)
99 	{
100 		int x = rand()%256;
101 		int y = rand()%256;
102 
103 		int z = rand()%256;
104 
105 		VectorFloat v((float)x, (float)y, (float)z/255.0f);
106 
107 		spline->setKey(i, v, (int)(((1.0f/((float)MAX_KEYS-1.0f))*(float)i)*MAX_TIME));
108 	}
109 
110 	drawSplines(spline, numBlocks, MAX_TIME, buffer, blockSize, (0*65536/255)>>1, (65536/255)>>1, (4*65536/255)>>1);
111 
112 	for (i = 0; i < 256*256; i++)
113 	{
114 		tex[i*3] = (int)(buffer[i*3]*255)>>16;
115 		tex[i*3+1] = (int)(buffer[i*3+1]*255)>>16;
116 		tex[i*3+2] = (int)(buffer[i*3+2]*255)>>16;
117 	}
118 
119 	delete[] buffer;
120 
121 	delete spline;
122 }
123 
createFlareTexture(unsigned char * tex,int r,int g,int b,float pw,unsigned int size)124 void Texture::createFlareTexture(unsigned char* tex,
125 								 int r,int g,int b,
126 								 float pw /*= 4.0f*/,
127 								 unsigned int size /*= 256*/)
128 {
129 
130 	int hx = size>>1;
131 	int hy = size>>1;
132 
133 	float maxlen = (float)sqrt(pow(size*0.5,2));
134 
135 	float fac = 1.0f/maxlen;
136 
137 	for (unsigned int y = 0; y < size; y++)
138 		for (unsigned int x = 0; x < size; x++)
139 		{
140 
141 			int offset = (y*size+x)*3;
142 
143 			int px = x - hx;
144 			int py = y - hy;
145 
146 			float v = (float)(px*px+py*py);
147 			float len = (float)sqrt(v);
148 
149 			if (len > maxlen)
150 				len = maxlen;
151 
152 			v = (float)(sin((1.0f-(len*fac))*(M_PI/2.0f)));
153 			float fc = (float)pow(v,pw);
154 
155 			//float fc = (float)pow(1.0f-(len*fac),pw);
156 
157 			tex[offset] = (unsigned char)(r*fc);
158 			tex[offset+1] = (unsigned char)(g*fc);
159 			tex[offset+2] = (unsigned char)(b*fc);
160 
161 		}
162 
163 }
164 
CalcLight(unsigned char * heightmap,int texmapsize,int x1,int y1,int x2,int y2,int depth,int smooth)165 static int CalcLight(unsigned char* heightmap, int texmapsize, int x1,int y1,int x2,int y2,int depth, int smooth)
166 {
167     int l,ran;
168     ran = (texmapsize<<smooth)>>depth;
169     l = (((int)heightmap[y1*texmapsize+x1]+(int)heightmap[y2*texmapsize+x2]) >> 1) + (rand()%ran)-(ran>>1);
170     if (l<1)
171         l = 1;
172     else if (l>255)
173         l = 255;
174 
175     return l;
176 }
177 
GenRandom(unsigned char * heightmap,int texmapsize,int x1,int y1,int x2,int y2,int depth,int smooth)178 static void GenRandom(unsigned char* heightmap, int texmapsize, int x1,int y1,int x2,int y2,int depth, int smooth)
179 {
180     int xh,yh;
181     int light;
182 
183     xh = (x1+x2) >> 1;
184     yh = (y1+y2) >> 1;
185     if (heightmap[y1*texmapsize+xh] == 0) heightmap[y1*texmapsize+xh] = CalcLight(heightmap, texmapsize,x1,y1,x2,y1,depth, smooth);
186     if (heightmap[y2*texmapsize+xh] == 0) heightmap[y2*texmapsize+xh] = CalcLight(heightmap, texmapsize,x1,y2,x2,y2,depth, smooth);
187     if (heightmap[yh*texmapsize+x1] == 0) heightmap[yh*texmapsize+x1] = CalcLight(heightmap, texmapsize,x1,y1,x1,y2,depth, smooth);
188     if (heightmap[yh*texmapsize+x2] == 0) heightmap[yh*texmapsize+x2] = CalcLight(heightmap, texmapsize,x2,y1,x2,y2,depth, smooth);
189 
190 	light = CalcLight(heightmap, texmapsize,x1,y1,x2,y2,depth, smooth) +
191 			CalcLight(heightmap, texmapsize,x1,y2,x2,y1,depth, smooth);
192 
193 	if (light>511)
194         light = 511;
195 
196 	heightmap[yh*texmapsize+xh] = light >> 1;
197 
198     if ((1<<depth) < texmapsize)
199     {
200         GenRandom(heightmap, texmapsize,x1,y1,xh,yh,depth+1, smooth);
201         GenRandom(heightmap, texmapsize,xh,y1,x2,yh,depth+1, smooth);
202         GenRandom(heightmap, texmapsize,x1,yh,xh,y2,depth+1, smooth);
203         GenRandom(heightmap, texmapsize,xh,yh,x2,y2,depth+1, smooth);
204     }
205 }
206 
GenPlasma(unsigned char * heightmap,int texmapsize,int smooth)207 static void GenPlasma(unsigned char* heightmap, int texmapsize, int smooth)
208 {
209     int i,x,y;
210 
211     memset(heightmap,0,texmapsize*texmapsize);
212     i = rand()&255;
213     heightmap[0*texmapsize+0]=i;
214     heightmap[0*texmapsize+(texmapsize-1)]=i;
215     heightmap[(texmapsize-1)*texmapsize+0]=i;
216     heightmap[(texmapsize-1)*texmapsize+(texmapsize-1)] = i;
217 
218     GenRandom(heightmap, texmapsize, 0,0,texmapsize-1,texmapsize-1,1, smooth);
219     for (y=1;y<=texmapsize-2;y++)
220         for (x=1;x<=texmapsize-2;x++)
221             heightmap[y*texmapsize+x] = 0;
222 
223     for (x = 0; x<=texmapsize-1; x++) heightmap[(texmapsize-1)*texmapsize+x] = heightmap[0*texmapsize+x];
224     for (y = 0; y<=texmapsize-1; y++) heightmap[y*texmapsize+(texmapsize-1)] = heightmap[y*texmapsize+0];
225     GenRandom(heightmap, texmapsize, 0,0,texmapsize-1,texmapsize-1,1, smooth);
226 }
227 
createPlasmaTexture(unsigned char * tex,unsigned int size,int smooth,int r,int g,int b)228 void Texture::createPlasmaTexture(unsigned char* tex, unsigned int size, int smooth, int r, int g, int b)
229 {
230 	unsigned char* map = new unsigned char[size*size];
231 
232 	GenPlasma(map, size, smooth);
233 
234 	for (unsigned int i = 0; i < size*size; i++)
235 	{
236 		tex[i*3] = (map[i]*r)/255;
237 		tex[i*3+1] = (map[i]*g)/255;
238 		tex[i*3+2] = (map[i]*b)/255;
239 	}
240 
241 	delete[] map;
242 }
243 
convert24to16(unsigned short * dstImage,unsigned char * srcImage,int size,unsigned int shifter)244 void Texture::convert24to16(unsigned short* dstImage, unsigned char* srcImage, int size, unsigned int shifter)
245 {
246 	for (int i = 0; i < size; i++)
247 		dstImage[i] = RGB2SHORT(srcImage[i*3]>>shifter,srcImage[i*3+1]>>shifter,srcImage[i*3+2]>>shifter);
248 }
249 
blur24(unsigned char * tex,unsigned int width,unsigned int height,unsigned int passes)250 void Texture::blur24(unsigned char* tex, unsigned int width, unsigned int height, unsigned int passes /*= 1*/)
251 {
252 	unsigned char* dst = new unsigned char[width*height*3];
253 
254 	memcpy(dst, tex, width*height*3);
255 
256 	for (unsigned int j = 0; j < passes; j++)
257 	{
258 
259 		for (unsigned int y = 1; y < height-1; y++)
260 			for (unsigned int x = 1; x < width-1; x++)
261 			{
262 
263 				int y1p = (y+1);
264 				int y1m = (y-1);
265 
266 				int x1p = (x+1);
267 				int x1m = (x-1);
268 
269 				for (int i = 0; i < 3; i++)
270 				{
271 
272 					int c = (tex[(y*width+x)*3+i] +
273 						tex[(y1m*width+x)*3+i] +
274 						tex[(y1p*width+x)*3+i] +
275 						tex[(y*width+x1m)*3+i] +
276 						tex[(y*width+x1p)*3+i])/5;
277 
278 					dst[(y*width+x)*3+i] = c;
279 				}
280 
281 			}
282 
283 
284 		memcpy(tex, dst, width*height*3);
285 	}
286 
287 	delete[] dst;
288 
289 }
290