added color envelope feature for tilemaps
[twcon.git] / src / game / client / render_map.cpp
blob23fa42e022dd57fd5f7f5e5dcafeca0e77b5f1c2
1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
3 #include <math.h>
4 #include <base/math.h>
5 #include <engine/graphics.h>
7 #include "render.h"
9 void CRenderTools::RenderEvalEnvelope(CEnvPoint *pPoints, int NumPoints, int Channels, float Time, float *pResult)
11 if(NumPoints == 0)
13 pResult[0] = 0;
14 pResult[1] = 0;
15 pResult[2] = 0;
16 pResult[3] = 0;
17 return;
20 if(NumPoints == 1)
22 pResult[0] = fx2f(pPoints[0].m_aValues[0]);
23 pResult[1] = fx2f(pPoints[0].m_aValues[1]);
24 pResult[2] = fx2f(pPoints[0].m_aValues[2]);
25 pResult[3] = fx2f(pPoints[0].m_aValues[3]);
26 return;
29 Time = fmod(Time, pPoints[NumPoints-1].m_Time/1000.0f)*1000.0f;
30 for(int i = 0; i < NumPoints-1; i++)
32 if(Time >= pPoints[i].m_Time && Time <= pPoints[i+1].m_Time)
34 float Delta = pPoints[i+1].m_Time-pPoints[i].m_Time;
35 float a = (Time-pPoints[i].m_Time)/Delta;
38 if(pPoints[i].m_Curvetype == CURVETYPE_SMOOTH)
39 a = -2*a*a*a + 3*a*a; // second hermite basis
40 else if(pPoints[i].m_Curvetype == CURVETYPE_SLOW)
41 a = a*a*a;
42 else if(pPoints[i].m_Curvetype == CURVETYPE_FAST)
44 a = 1-a;
45 a = 1-a*a*a;
47 else if (pPoints[i].m_Curvetype == CURVETYPE_STEP)
48 a = 0;
49 else
51 // linear
54 for(int c = 0; c < Channels; c++)
56 float v0 = fx2f(pPoints[i].m_aValues[c]);
57 float v1 = fx2f(pPoints[i+1].m_aValues[c]);
58 pResult[c] = v0 + (v1-v0) * a;
61 return;
65 pResult[0] = fx2f(pPoints[NumPoints-1].m_aValues[0]);
66 pResult[1] = fx2f(pPoints[NumPoints-1].m_aValues[1]);
67 pResult[2] = fx2f(pPoints[NumPoints-1].m_aValues[2]);
68 pResult[3] = fx2f(pPoints[NumPoints-1].m_aValues[3]);
69 return;
73 static void Rotate(CPoint *pCenter, CPoint *pPoint, float Rotation)
75 int x = pPoint->x - pCenter->x;
76 int y = pPoint->y - pCenter->y;
77 pPoint->x = (int)(x * cosf(Rotation) - y * sinf(Rotation) + pCenter->x);
78 pPoint->y = (int)(x * sinf(Rotation) + y * cosf(Rotation) + pCenter->y);
81 void CRenderTools::RenderQuads(CQuad *pQuads, int NumQuads, int RenderFlags, ENVELOPE_EVAL pfnEval, void *pUser)
83 Graphics()->QuadsBegin();
84 float Conv = 1/255.0f;
85 for(int i = 0; i < NumQuads; i++)
87 CQuad *q = &pQuads[i];
89 float r=1, g=1, b=1, a=1;
91 if(q->m_ColorEnv >= 0)
93 float aChannels[4];
94 pfnEval(q->m_ColorEnvOffset/1000.0f, q->m_ColorEnv, aChannels, pUser);
95 r = aChannels[0];
96 g = aChannels[1];
97 b = aChannels[2];
98 a = aChannels[3];
101 bool Opaque = false;
102 if(a < 0.01f || (q->m_aColors[0].a < 0.01f && q->m_aColors[1].a < 0.01f && q->m_aColors[2].a < 0.01f && q->m_aColors[3].a < 0.01f))
103 Opaque = true;
105 if(Opaque && !(RenderFlags&LAYERRENDERFLAG_OPAQUE))
106 continue;
107 if(!Opaque && !(RenderFlags&LAYERRENDERFLAG_TRANSPARENT))
108 continue;
110 Graphics()->QuadsSetSubsetFree(
111 fx2f(q->m_aTexcoords[0].x), fx2f(q->m_aTexcoords[0].y),
112 fx2f(q->m_aTexcoords[1].x), fx2f(q->m_aTexcoords[1].y),
113 fx2f(q->m_aTexcoords[2].x), fx2f(q->m_aTexcoords[2].y),
114 fx2f(q->m_aTexcoords[3].x), fx2f(q->m_aTexcoords[3].y)
117 float OffsetX = 0;
118 float OffsetY = 0;
119 float Rot = 0;
121 // TODO: fix this
122 if(q->m_PosEnv >= 0)
124 float aChannels[4];
125 pfnEval(q->m_PosEnvOffset/1000.0f, q->m_PosEnv, aChannels, pUser);
126 OffsetX = aChannels[0];
127 OffsetY = aChannels[1];
128 Rot = aChannels[2]/360.0f*pi*2;
131 IGraphics::CColorVertex Array[4] = {
132 IGraphics::CColorVertex(0, q->m_aColors[0].r*Conv*r, q->m_aColors[0].g*Conv*g, q->m_aColors[0].b*Conv*b, q->m_aColors[0].a*Conv*a),
133 IGraphics::CColorVertex(1, q->m_aColors[1].r*Conv*r, q->m_aColors[1].g*Conv*g, q->m_aColors[1].b*Conv*b, q->m_aColors[1].a*Conv*a),
134 IGraphics::CColorVertex(2, q->m_aColors[2].r*Conv*r, q->m_aColors[2].g*Conv*g, q->m_aColors[2].b*Conv*b, q->m_aColors[2].a*Conv*a),
135 IGraphics::CColorVertex(3, q->m_aColors[3].r*Conv*r, q->m_aColors[3].g*Conv*g, q->m_aColors[3].b*Conv*b, q->m_aColors[3].a*Conv*a)};
136 Graphics()->SetColorVertex(Array, 4);
138 CPoint *pPoints = q->m_aPoints;
140 if(Rot != 0)
142 static CPoint aRotated[4];
143 aRotated[0] = q->m_aPoints[0];
144 aRotated[1] = q->m_aPoints[1];
145 aRotated[2] = q->m_aPoints[2];
146 aRotated[3] = q->m_aPoints[3];
147 pPoints = aRotated;
149 Rotate(&q->m_aPoints[4], &aRotated[0], Rot);
150 Rotate(&q->m_aPoints[4], &aRotated[1], Rot);
151 Rotate(&q->m_aPoints[4], &aRotated[2], Rot);
152 Rotate(&q->m_aPoints[4], &aRotated[3], Rot);
155 IGraphics::CFreeformItem Freeform(
156 fx2f(pPoints[0].x)+OffsetX, fx2f(pPoints[0].y)+OffsetY,
157 fx2f(pPoints[1].x)+OffsetX, fx2f(pPoints[1].y)+OffsetY,
158 fx2f(pPoints[2].x)+OffsetX, fx2f(pPoints[2].y)+OffsetY,
159 fx2f(pPoints[3].x)+OffsetX, fx2f(pPoints[3].y)+OffsetY);
160 Graphics()->QuadsDrawFreeform(&Freeform, 1);
162 Graphics()->QuadsEnd();
165 void CRenderTools::RenderTilemap(CTile *pTiles, int w, int h, float Scale, vec4 Color, int RenderFlags,
166 ENVELOPE_EVAL pfnEval, void *pUser, int ColorEnv, int ColorEnvOffset)
168 //Graphics()->TextureSet(img_get(tmap->image));
169 float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
170 Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
171 //Graphics()->MapScreen(screen_x0-50, screen_y0-50, screen_x1+50, screen_y1+50);
173 // calculate the final pixelsize for the tiles
174 float TilePixelSize = 1024/32.0f;
175 float FinalTileSize = Scale/(ScreenX1-ScreenX0) * Graphics()->ScreenWidth();
176 float FinalTilesetScale = FinalTileSize/TilePixelSize;
178 float r=1, g=1, b=1, a=1;
179 if(ColorEnv >= 0)
181 float aChannels[4];
182 pfnEval(ColorEnvOffset/1000.0f, ColorEnv, aChannels, pUser);
183 r = aChannels[0];
184 g = aChannels[1];
185 b = aChannels[2];
186 a = aChannels[3];
189 Graphics()->QuadsBegin();
190 Graphics()->SetColor(Color.r*r, Color.g*g, Color.b*b, Color.a*a);
192 int StartY = (int)(ScreenY0/Scale)-1;
193 int StartX = (int)(ScreenX0/Scale)-1;
194 int EndY = (int)(ScreenY1/Scale)+1;
195 int EndX = (int)(ScreenX1/Scale)+1;
197 // adjust the texture shift according to mipmap level
198 float TexSize = 1024.0f;
199 float Frac = (1.25f/TexSize) * (1/FinalTilesetScale);
200 float Nudge = (0.5f/TexSize) * (1/FinalTilesetScale);
202 for(int y = StartY; y < EndY; y++)
203 for(int x = StartX; x < EndX; x++)
205 int mx = x;
206 int my = y;
208 if(RenderFlags&TILERENDERFLAG_EXTEND)
210 if(mx<0)
211 mx = 0;
212 if(mx>=w)
213 mx = w-1;
214 if(my<0)
215 my = 0;
216 if(my>=h)
217 my = h-1;
219 else
221 if(mx<0)
222 continue; // mx = 0;
223 if(mx>=w)
224 continue; // mx = w-1;
225 if(my<0)
226 continue; // my = 0;
227 if(my>=h)
228 continue; // my = h-1;
231 int c = mx + my*w;
233 unsigned char Index = pTiles[c].m_Index;
234 if(Index)
236 unsigned char Flags = pTiles[c].m_Flags;
238 bool Render = false;
239 if(Flags&TILEFLAG_OPAQUE)
241 if(RenderFlags&LAYERRENDERFLAG_OPAQUE)
242 Render = true;
244 else
246 if(RenderFlags&LAYERRENDERFLAG_TRANSPARENT)
247 Render = true;
250 if(Render)
253 int tx = Index%16;
254 int ty = Index/16;
255 int Px0 = tx*(1024/16);
256 int Py0 = ty*(1024/16);
257 int Px1 = Px0+(1024/16)-1;
258 int Py1 = Py0+(1024/16)-1;
260 float x0 = Nudge + Px0/TexSize+Frac;
261 float y0 = Nudge + Py0/TexSize+Frac;
262 float x1 = Nudge + Px1/TexSize-Frac;
263 float y1 = Nudge + Py0/TexSize+Frac;
264 float x2 = Nudge + Px1/TexSize-Frac;
265 float y2 = Nudge + Py1/TexSize-Frac;
266 float x3 = Nudge + Px0/TexSize+Frac;
267 float y3 = Nudge + Py1/TexSize-Frac;
269 if(Flags&TILEFLAG_VFLIP)
271 x0 = x2;
272 x1 = x3;
273 x2 = x3;
274 x3 = x0;
277 if(Flags&TILEFLAG_HFLIP)
279 y0 = y3;
280 y2 = y1;
281 y3 = y1;
282 y1 = y0;
285 if(Flags&TILEFLAG_ROTATE)
287 float Tmp = x0;
288 x0 = x3;
289 x3 = x2;
290 x2 = x1;
291 x1 = Tmp;
292 Tmp = y0;
293 y0 = y3;
294 y3 = y2;
295 y2 = y1;
296 y1 = Tmp;
299 Graphics()->QuadsSetSubsetFree(x0, y0, x1, y1, x2, y2, x3, y3);
300 IGraphics::CQuadItem QuadItem(x*Scale, y*Scale, Scale, Scale);
301 Graphics()->QuadsDrawTL(&QuadItem, 1);
304 x += pTiles[c].m_Skip;
307 Graphics()->QuadsEnd();
308 Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1);