the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "Tesselator.h"
3#include "..\Minecraft.World\BasicTypeContainers.h"
4#include "..\Minecraft.World\FloatBuffer.h"
5#include "..\Minecraft.World\IntBuffer.h"
6#include "..\Minecraft.World\ByteBuffer.h"
7
8bool Tesselator::TRIANGLE_MODE = false;
9bool Tesselator::USE_VBO = false;
10
11/* Things to check we are intialising in the constructor...
12
13
14
15double u, v;
16int col;
17int mode;
18double xo, yo, zo;
19int normal;
20
21
22
23
24
25
26*/
27DWORD Tesselator::tlsIdx = TlsAlloc();
28
29Tesselator *Tesselator::getInstance()
30{
31 return (Tesselator *)TlsGetValue(tlsIdx);
32}
33
34void Tesselator::CreateNewThreadStorage(int bytes)
35{
36 Tesselator *instance = new Tesselator(bytes/4);
37 TlsSetValue(tlsIdx, instance);
38}
39
40Tesselator::Tesselator(int size)
41{
42 // 4J - this block of things moved to constructor from general initialisations round Java class
43 vertices = 0;
44 hasColor = false;
45 hasTexture = false;
46 hasTexture2 = false;
47 hasNormal = false;
48 p = 0;
49 count = 0;
50 _noColor = false;
51 tesselating = false;
52 vboMode = false;
53 vboId = 0;
54 vboCounts = 10;
55
56 // 4J - adding these things to constructor just to be sure that they are initialised with something
57 u = v = 0;
58 col = 0;
59 mode = 0;
60 xo = yo = zo = 0;
61 xoo = yoo = zoo = 0; // 4J added
62 _normal = 0;
63
64 useCompactFormat360 = false; // 4J added
65 mipmapEnable = true; // 4J added
66 useProjectedTexturePixelShader = false; // 4J added
67
68 this->size = size;
69
70 _array = new intArray(size);
71
72 vboMode = USE_VBO; // 4J removed - && GLContext.getCapabilities().GL_ARB_vertex_buffer_object;
73 if (vboMode)
74 {
75 vboIds = MemoryTracker::createIntBuffer(vboCounts);
76 ARBVertexBufferObject::glGenBuffersARB(vboIds);
77 }
78
79#ifdef __PSVITA__
80 // AP - alpha cut out is expensive on vita. Use this to defer primitives that use icons with alpha
81 alphaCutOutEnabled = false;
82
83 // this is the cut out enabled vertex array
84 _array2 = new intArray(size);
85 vertices2 = 0;
86 p2 = 0;
87#endif
88}
89
90Tesselator *Tesselator::getUniqueInstance(int size)
91{
92 return new Tesselator(size);
93}
94
95void Tesselator::end()
96{
97// if (!tesselating) throw new IllegalStateException("Not tesselating!"); // 4J - removed
98 tesselating = false;
99#ifdef __PSVITA__
100 // AP - alpha cut out is expensive on vita. Check both counts for valid vertices
101 if( vertices > 0 || vertices2 > 0 )
102#else
103 if (vertices > 0)
104#endif
105 {
106 // 4J - a lot of stuff taken out here for fiddling round with enable client states etc.
107 // that don't matter for our renderer
108 if (!hasColor)
109 {
110 // 4J - TEMP put in fixed vertex colors if we don't have any, until we have a shader that can cope without them
111 unsigned int *pColData = (unsigned int *)_array->data;
112 pColData += 5;
113 for( int i = 0; i < vertices; i++ )
114 {
115 *pColData = 0xffffffff;
116 pColData += 8;
117 }
118#ifdef __PSVITA__
119 // AP - alpha cut out is expensive on vita. Check both counts for valid vertices
120 pColData = (unsigned int *)_array2->data;
121 pColData += 5;
122 for( int i = 0; i < vertices2; i++ )
123 {
124 *pColData = 0xffffffff;
125 pColData += 8;
126 }
127#endif
128 }
129 if (mode == GL_QUADS && TRIANGLE_MODE)
130 {
131 // glDrawArrays(GL_TRIANGLES, 0, vertices); // 4J - changed for xbox
132#ifdef _XBOX
133 RenderManager.DrawVertices(D3DPT_TRIANGLELIST,vertices,_array->data,
134 useCompactFormat360?C4JRender::VERTEX_TYPE_PS3_TS2_CS1:C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1,
135 useProjectedTexturePixelShader?C4JRender::PIXEL_SHADER_TYPE_PROJECTION:C4JRender::PIXEL_SHADER_TYPE_STANDARD);
136#else
137 RenderManager.DrawVertices(C4JRender::PRIMITIVE_TYPE_TRIANGLE_LIST,vertices,_array->data,
138 useCompactFormat360?C4JRender::VERTEX_TYPE_COMPRESSED:C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1,
139 useProjectedTexturePixelShader?C4JRender::PIXEL_SHADER_TYPE_PROJECTION:C4JRender::PIXEL_SHADER_TYPE_STANDARD);
140#endif
141 }
142 else
143 {
144// glDrawArrays(mode, 0, vertices); // 4J - changed for xbox
145 // For compact vertices, the vertexCount has to be calculated from the amount of data written, as
146 // we insert extra fake vertices to encode supplementary data for more awkward quads that have non
147 // axis aligned UVs (eg flowing lava/water)
148#ifdef _XBOX
149 int vertexCount = vertices;
150 if( useCompactFormat360 )
151 {
152 vertexCount = p / 2;
153 RenderManager.DrawVertices((D3DPRIMITIVETYPE)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_PS3_TS2_CS1, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
154 }
155 else
156 {
157 if( useProjectedTexturePixelShader )
158 {
159 RenderManager.DrawVertices((D3DPRIMITIVETYPE)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN, C4JRender::PIXEL_SHADER_TYPE_PROJECTION);
160 }
161 else
162 {
163 RenderManager.DrawVertices((D3DPRIMITIVETYPE)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
164 }
165 }
166#else
167 int vertexCount = vertices;
168 if( useCompactFormat360 )
169 {
170#ifdef __PSVITA__
171 // AP - alpha cut out is expensive on vita. Render non-cut out stuff first then send the cut out stuff
172 if( vertexCount )
173 {
174 RenderManager.DrawVertices((C4JRender::ePrimitiveType)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_COMPRESSED, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
175 }
176 if( vertices2 )
177 {
178 RenderManager.DrawVerticesCutOut((C4JRender::ePrimitiveType)mode,vertices2,_array2->data,C4JRender::VERTEX_TYPE_COMPRESSED, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
179 }
180#else
181
182 RenderManager.DrawVertices((C4JRender::ePrimitiveType)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_COMPRESSED, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
183#endif
184 }
185 else
186 {
187 if( useProjectedTexturePixelShader )
188 {
189 RenderManager.DrawVertices((C4JRender::ePrimitiveType)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN, C4JRender::PIXEL_SHADER_TYPE_PROJECTION);
190 }
191 else
192 {
193 RenderManager.DrawVertices((C4JRender::ePrimitiveType)mode,vertexCount,_array->data,C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1, C4JRender::PIXEL_SHADER_TYPE_STANDARD);
194 }
195 }
196#endif
197 }
198 glDisableClientState(GL_VERTEX_ARRAY);
199 if (hasTexture) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
200 if (hasColor) glDisableClientState(GL_COLOR_ARRAY);
201 if (hasNormal) glDisableClientState(GL_NORMAL_ARRAY);
202 }
203
204 clear();
205}
206
207void Tesselator::clear()
208{
209 vertices = 0;
210
211 p = 0;
212 count = 0;
213
214#ifdef __PSVITA__
215 // AP - alpha cut out is expensive on vita. Clear the cut out variables
216 vertices2 = 0;
217 p2 = 0;
218#endif
219}
220
221void Tesselator::begin()
222{
223 begin(GL_QUADS);
224 bounds.reset(); // 4J MGH - added
225}
226
227void Tesselator::useProjectedTexture(bool enable)
228{
229 useProjectedTexturePixelShader = enable;
230}
231
232void Tesselator::useCompactVertices(bool enable)
233{
234 useCompactFormat360 = enable;
235}
236
237bool Tesselator::getCompactVertices()
238{
239 return useCompactFormat360;
240}
241
242bool Tesselator::setMipmapEnable(bool enable)
243{
244 bool prev = mipmapEnable;
245 mipmapEnable = enable;
246 return prev;
247}
248
249#ifdef __PSVITA__
250// AP - alpha cut out is expensive on vita. Use this to defer primitives that use icons with alpha
251void Tesselator::setAlphaCutOut(bool enable)
252{
253 alphaCutOutEnabled = enable;
254}
255
256// AP - was any cut out geometry added since the last call to Clear
257bool Tesselator::getCutOutFound()
258{
259 if( vertices2 )
260 return true;
261
262 return false;
263}
264#endif
265
266void Tesselator::begin(int mode)
267{
268 /* // 4J - removed
269 if (tesselating) {
270 throw new IllegalStateException("Already tesselating!");
271 } */
272 tesselating = true;
273
274 clear();
275 this->mode = mode;
276 hasNormal = false;
277 hasColor = false;
278 hasTexture = false;
279 hasTexture2 = false;
280 _noColor = false;
281}
282
283void Tesselator::tex(float u, float v)
284{
285 hasTexture = true;
286 this->u = u;
287 this->v = v;
288}
289
290void Tesselator::tex2(int tex2)
291{
292 hasTexture2 = true;
293 this->_tex2 = tex2;
294}
295
296void Tesselator::color(float r, float g, float b)
297{
298 color((int) (r * 255), (int) (g * 255), (int) (b * 255));
299}
300
301void Tesselator::color(float r, float g, float b, float a)
302{
303 color((int) (r * 255), (int) (g * 255), (int) (b * 255), (int) (a * 255));
304}
305
306void Tesselator::color(int r, int g, int b)
307{
308 color(r, g, b, 255);
309}
310
311void Tesselator::color(int r, int g, int b, int a)
312{
313 if (_noColor) return;
314
315 if (r > 255) r = 255;
316 if (g > 255) g = 255;
317 if (b > 255) b = 255;
318 if (a > 255) a = 255;
319 if (r < 0) r = 0;
320 if (g < 0) g = 0;
321 if (b < 0) b = 0;
322 if (a < 0) a = 0;
323
324 hasColor = true;
325 // 4J - removed little-endian option
326 col = (r << 24) | (g << 16) | (b << 8) | (a);
327}
328
329void Tesselator::color(byte r, byte g, byte b)
330{
331 color(r & 0xff, g & 0xff, b & 0xff);
332}
333
334void Tesselator::vertexUV(float x, float y, float z, float u, float v)
335{
336 tex(u, v);
337 vertex(x, y, z);
338}
339
340// Pack the 4 vertices of a quad up into a compact format. This is structured as 8 bytes per vertex,
341// arranged in blocks of 4 vertices per quad. Currently this is (one letter per nyblle):
342//
343// cccc xxyy zzll rgbi (vertex 0)
344// umin xxyy zzll rgbi (vertex 1)
345// vmin xxyy zzll rgbi (vertex 2)
346// udvd xxyy zzll rgbi (vertex 3)
347//
348// where: cccc is a 15-bit (5 bits per x/y/z) origin position / offset for the whole quad. Each
349// component is unsigned, and offset by 16 so has a range 0 to 31 actually representing -16 to 15
350// xx,yy,zz are 8-bit deltas from this origin to each vertex. These are unsigned 1.7 fixed point, ie
351// representing a range of 0 to 1.9921875
352// rgb is 4:4:4 RGB
353// umin, vmin are 3:13 unsigned fixed point UVs reprenting the min u and v required by the quad
354// ud,vd are 8-bit unsigned fixed pont UV deltas, which can be added to umin/vmin to get umax, vmax
355// and therefore define the 4 corners of an axis aligned UV mapping
356// i is a code per vertex that indicates which of umin/umax should be used for u, and which
357// of vmin/vmax should be used for v for this vertex. The coding is:
358// 0 - u = umin, v = vmin
359// 1 - u = umin, v = vmax
360// 2 - u = umax, v = vmin
361// 3 - u = umax, v = vmax
362// 4 - not axis aligned, use uv stored in the vertex data 4 on from this one
363// ll is an 8-bit (4 bit per u/v) index into the current lighting texture
364//
365// For quads that don't have axis aligned UVs (ie have a code for 4 in i as described above) the 8 byte vertex
366// is followed by a further 8 bytes which have explicit UVs defined for each vertex:
367//
368// 0000 0000 uuuu vvvv (vertex 0)
369// 0000 0000 uuuu vvvv (vertex 1)
370// 0000 0000 uuuu vvvv (vertex 2)
371// 0000 0000 uuuu vvvv (vertex 3)
372//
373
374void Tesselator::packCompactQuad()
375{
376 // Offset x/y/z by 16 so that we can deal with a -16 -> 16 range
377 for( int i = 0; i < 4; i++ )
378 {
379 m_ix[i] += 16 * 128;
380 m_iy[i] += 16 * 128;
381 m_iz[i] += 16 * 128;
382 }
383 // Find min x/y/z
384 unsigned int minx = m_ix[0];
385 unsigned int miny = m_iy[0];
386 unsigned int minz = m_iz[0];
387 for( int i = 1; i < 4; i++ )
388 {
389 if( m_ix[i] < minx ) minx = m_ix[i];
390 if( m_iy[i] < miny ) miny = m_iy[i];
391 if( m_iz[i] < minz ) minz = m_iz[i];
392 }
393 // Everything has been scaled by a factor of 128 to get it into an int, and so
394 // the minimum now should be in the range of (0->32) * 128. Get the base x/y/z
395 // that our quad will be referenced from now, which can be stored in 5 bits
396 unsigned int basex = ( minx >> 7 );
397 unsigned int basey = ( miny >> 7 );
398 unsigned int basez = ( minz >> 7 );
399 // If the min is 32, then this whole quad must be in that plane - make the min 15 instead so
400 // we can still offset from that with our delta to get to the exact edge
401 if( basex == 32 ) basex = 31;
402 if( basey == 32 ) basey = 31;
403 if( basez == 32 ) basez = 31;
404 // Now get deltas to each vertex - these have an 8-bit range so they can span a
405 // full unit range from the base position
406 for( int i = 0; i < 4; i++ )
407 {
408 m_ix[i] -= basex << 7;
409 m_iy[i] -= basey << 7;
410 m_iz[i] -= basez << 7;
411 }
412 // Now write the data out
413 unsigned int *data = (unsigned int *)&_array->data[p];
414
415 for( int i = 0; i < 4; i++ )
416 {
417 data[i * 2 + 0] = ( m_ix[i] << 8 ) | ( m_iy[i] );
418 data[i * 2 + 1] = ( m_iz[i] << 24 ) | ( m_clr[i] );
419 }
420 data[0] |= ( basex << 26 ) | ( basey << 21 )| ( basez << 16 );
421
422 // Now process UVs. First find min & max U & V
423 unsigned int minu = m_u[0];
424 unsigned int minv = m_v[0];
425 unsigned int maxu = m_u[0];
426 unsigned int maxv = m_v[0];
427
428 for( int i = 1; i < 4; i++ )
429 {
430 if( m_u[i] < minu ) minu = m_u[i];
431 if( m_v[i] < minv ) minv = m_v[i];
432 if( m_u[i] > maxu ) maxu = m_u[i];
433 if( m_v[i] > maxv ) maxv = m_v[i];
434 }
435 // In nearly all cases, all our UVs should be axis aligned for this quad. So the only values they should
436 // have in each dimension should be the min/max. We're going to store:
437 // (1) minu/maxu (16 bits each, only actuall needs to store 14 bits to get a 0 to 2 range for each
438 // (2) du/dv ( ie maxu-minu, maxv-minv) - 8 bits each, to store a range of 0 to 15.9375 texels. This
439 // should be enough to map the full UV range of a single 16x16 region of the terrain texture, since
440 // we always pull UVs in by 1/16th of their range at the sides
441 unsigned int du = maxu - minu;
442 unsigned int dv = maxv - minv;
443 if( du > 255 ) du = 255;
444 if( dv > 255 ) dv = 255;
445 // Check if this quad has UVs that can be referenced this way. This should only happen for flowing water
446 // and lava, where the texture coordinates are rotated for the top surface of the tile.
447 bool axisAligned = true;
448 for( int i = 0; i < 4; i++ )
449 {
450 if(! ( ( ( m_u[i] == minu ) || ( m_u[i] == maxu ) ) &&
451 ( ( m_v[i] == minv ) || ( m_v[i] == maxv ) ) ) )
452 {
453 axisAligned = false;
454 }
455 }
456
457 if( axisAligned )
458 {
459 // Now go through each vertex, and work out which of the min/max should be used for each dimension,
460 // and store
461 for( int i = 0; i < 4; i++ )
462 {
463 unsigned int code = 0;
464 if( m_u[i] == maxu ) code |= 2;
465 if( m_v[i] == maxv ) code |= 1;
466 data[i * 2 + 1] |= code;
467 data[i * 2 + 1] |= m_t2[i] << 16;
468 }
469 // Finally, store the minu/minv/du/dv
470 data[1 * 2 + 0] |= minu << 16;
471 data[2 * 2 + 0] |= minv << 16;
472 data[3 * 2 + 0] |= ( du << 24 | dv << 16 );
473
474 p += 4 * 2;
475 }
476 else
477 {
478 // The UVs aren't axis aligned - store them in the next 4 vertices. These will be indexed from
479 // our base vertices because we'll set a special code (4) for the UVs. They won't be drawn as actual
480 // verts when these extra vertices go through the vertex shader, because we'll make sure that
481 // they get interpreted as a zero area quad and so they'll be quickly eliminated from rendering post-tranform
482
483 for( int i = 0; i < 4; i++ )
484 {
485 data[i * 2 + 1] |= ( 4 ); // The special code to indicate they need further data to be fetched
486 data[i * 2 + 1] |= m_t2[i] << 16;
487 data[8 + i * 2] = 0; // This includes x/y coordinate of each vert as (0,0) so they will be interpreted as a zero area quad
488 data[9 + i * 2] = m_u[i] << 16 | m_v[i];
489 }
490
491 // Extra 8 bytes required
492 p += 8 * 2;
493 }
494}
495
496#ifdef __PSVITA__
497void Tesselator::tileQuad(float x1, float y1, float z1, float u1, float v1, float r1, float g1, float b1, int tex1,
498 float x2, float y2, float z2, float u2, float v2, float r2, float g2, float b2, int tex2,
499 float x3, float y3, float z3, float u3, float v3, float r3, float g3, float b3, int tex3,
500 float x4, float y4, float z4, float u4, float v4, float r4, float g4, float b4, int tex4
501 )
502{
503 hasTexture = true;
504 hasTexture2 = true;
505 hasColor = true;
506
507 count+=4;
508
509 // AP - alpha cut out is expensive on vita. This will choose the correct data buffer depending on cut out enabled
510 int16_t* pShortData;
511 if( !alphaCutOutEnabled )
512 {
513 pShortData = (int16_t*)&_array->data[p];
514 p += 16;
515 vertices+=4;
516 }
517 else
518 {
519 pShortData = (int16_t*)&_array2->data[p2];
520 p2 += 16;
521 vertices2+=4;
522 }
523
524 int r = ((int) (r1 * 31)) << 11;
525 int g = ((int) (g1 * 63)) << 5;
526 int b = ((int) (b1 * 31));
527 int ipackedcol = r | g | b;
528 ipackedcol -= 32768; // -32768 to 32767 range
529 ipackedcol &= 0xffff;
530
531 bounds.addVert(x1+xo, y1+yo, z1+zo); // 4J MGH - added
532 pShortData[0] = (((int)((x1 + xo ) * 1024.0f))&0xffff);
533 pShortData[1] = (((int)((y1 + yo ) * 1024.0f))&0xffff);
534 pShortData[2] = (((int)((z1 + zo ) * 1024.0f))&0xffff);
535 pShortData[3] = ipackedcol;
536 pShortData[4] = (((int)(u1 * 8192.0f))&0xffff);
537 pShortData[5] = (((int)(v1 * 8192.0f))&0xffff);
538 ((int *)pShortData)[3] = tex1;
539 pShortData += 8;
540
541 r = ((int) (r2 * 31)) << 11;
542 g = ((int) (g2 * 63)) << 5;
543 b = ((int) (b2 * 31));
544 ipackedcol = r | g | b;
545 ipackedcol -= 32768; // -32768 to 32767 range
546 ipackedcol &= 0xffff;
547
548 bounds.addVert(x2+xo, y2+yo, z2+zo); // 4J MGH - added
549 pShortData[0] = (((int)((x2 + xo ) * 1024.0f))&0xffff);
550 pShortData[1] = (((int)((y2 + yo ) * 1024.0f))&0xffff);
551 pShortData[2] = (((int)((z2 + zo ) * 1024.0f))&0xffff);
552 pShortData[3] = ipackedcol;
553 pShortData[4] = (((int)(u2 * 8192.0f))&0xffff);
554 pShortData[5] = (((int)(v2 * 8192.0f))&0xffff);
555 ((int *)pShortData)[3] = tex2;
556 pShortData += 8;
557
558 r = ((int) (r3 * 31)) << 11;
559 g = ((int) (g3 * 63)) << 5;
560 b = ((int) (b3 * 31));
561 ipackedcol = r | g | b;
562 ipackedcol -= 32768; // -32768 to 32767 range
563 ipackedcol &= 0xffff;
564
565 bounds.addVert(x3+xo, y3+yo, z3+zo); // 4J MGH - added
566 pShortData[0] = (((int)((x3 + xo ) * 1024.0f))&0xffff);
567 pShortData[1] = (((int)((y3 + yo ) * 1024.0f))&0xffff);
568 pShortData[2] = (((int)((z3 + zo ) * 1024.0f))&0xffff);
569 pShortData[3] = ipackedcol;
570 pShortData[4] = (((int)(u3 * 8192.0f))&0xffff);
571 pShortData[5] = (((int)(v3 * 8192.0f))&0xffff);
572 ((int *)pShortData)[3] = tex3;
573 pShortData += 8;
574
575 r = ((int) (r4 * 31)) << 11;
576 g = ((int) (g4 * 63)) << 5;
577 b = ((int) (b4 * 31));
578 ipackedcol = r | g | b;
579 ipackedcol -= 32768; // -32768 to 32767 range
580 ipackedcol &= 0xffff;
581
582 bounds.addVert(x4+xo, y4+yo, z4+zo); // 4J MGH - added
583 pShortData[0] = (((int)((x4 + xo ) * 1024.0f))&0xffff);
584 pShortData[1] = (((int)((y4 + yo ) * 1024.0f))&0xffff);
585 pShortData[2] = (((int)((z4 + zo ) * 1024.0f))&0xffff);
586 pShortData[3] = ipackedcol;
587 pShortData[4] = (((int)(u4 * 8192.0f))&0xffff);
588 pShortData[5] = (((int)(v4 * 8192.0f))&0xffff);
589 ((int *)pShortData)[3] = tex4;
590
591 // Max 65535 verts in D3D, so 65532 is the last point at the end of a quad to catch it
592 if ( (!alphaCutOutEnabled && vertices % 4 == 0 && ( ( p >= size - 4 * 4 ) || ( ( p / 4 ) >= 65532 ) )) ||
593 (alphaCutOutEnabled && vertices2 % 4 == 0 && ( ( p2 >= size - 4 * 4 ) || ( ( p2 / 4 ) >= 65532 ) )) )
594 {
595 end();
596 tesselating = true;
597 }
598}
599
600void Tesselator::tileRainQuad(float x1, float y1, float z1, float u1, float v1,
601 float x2, float y2, float z2, float u2, float v2,
602 float x3, float y3, float z3, float u3, float v3,
603 float x4, float y4, float z4, float u4, float v4,
604 float r1, float g1, float b1, float a1,
605 float r2, float g2, float b2, float a2,
606 int tex1
607 )
608{
609 hasTexture = true;
610 hasTexture2 = true;
611 hasColor = true;
612
613 float* pfData = (float*)&_array->data[p];
614
615 count+=4;
616 p += 4 * 8;
617 vertices+=4;
618
619 unsigned int col1 = ((int)(r1*255) << 24) | ((int)(g1*255) << 16) | ((int)(b1*255) << 8) | (int)(a1*255);
620
621 bounds.addVert(x1+xo, y1+yo, z1+zo);
622 pfData[0] = (x1 + xo);
623 pfData[1] = (y1 + yo);
624 pfData[2] = (z1 + zo);
625 pfData[3] = u1;
626 pfData[4] = v1;
627 ((int*)pfData)[5] = col1;
628 ((int*)pfData)[7] = tex1;
629 pfData += 8;
630
631 bounds.addVert(x2+xo, y2+yo, z2+zo);
632 pfData[0] = (x2 + xo);
633 pfData[1] = (y2 + yo);
634 pfData[2] = (z2 + zo);
635 pfData[3] = u2;
636 pfData[4] = v2;
637 ((int*)pfData)[5] = col1;
638 ((int*)pfData)[7] = tex1;
639 pfData += 8;
640
641 col1 = ((int)(r2*255) << 24) | ((int)(g2*255) << 16) | ((int)(b2*255) << 8) | (int)(a2*255);
642
643 bounds.addVert(x3+xo, y3+yo, z3+zo);
644 pfData[0] = (x3 + xo);
645 pfData[1] = (y3 + yo);
646 pfData[2] = (z3 + zo);
647 pfData[3] = u3;
648 pfData[4] = v3;
649 ((int*)pfData)[5] = col1;
650 ((int*)pfData)[7] = tex1;
651 pfData += 8;
652
653 bounds.addVert(x4+xo, y4+yo, z4+zo);
654 pfData[0] = (x4 + xo);
655 pfData[1] = (y4 + yo);
656 pfData[2] = (z4 + zo);
657 pfData[3] = u4;
658 pfData[4] = v4;
659 ((int*)pfData)[5] = col1;
660 ((int*)pfData)[7] = tex1;
661 pfData += 8;
662
663 if (vertices % 4 == 0 && p >= size - 8 * 4)
664 {
665 end();
666 tesselating = true;
667 }
668}
669
670void Tesselator::tileParticleQuad(float x1, float y1, float z1, float u1, float v1,
671 float x2, float y2, float z2, float u2, float v2,
672 float x3, float y3, float z3, float u3, float v3,
673 float x4, float y4, float z4, float u4, float v4,
674 float r1, float g1, float b1, float a1)
675{
676 hasTexture = true;
677 hasTexture2 = true;
678 hasColor = true;
679
680 float* pfData = (float*)&_array->data[p];
681
682 count+=4;
683 p += 4 * 8;
684 vertices+=4;
685
686 unsigned int col1 = ((int)(r1*255) << 24) | ((int)(g1*255) << 16) | ((int)(b1*255) << 8) | (int)(a1*255);
687
688 bounds.addVert(x1+xo, y1+yo, z1+zo);
689 pfData[0] = (x1 + xo);
690 pfData[1] = (y1 + yo);
691 pfData[2] = (z1 + zo);
692 pfData[3] = u1;
693 pfData[4] = v1;
694 ((int*)pfData)[5] = col1;
695 ((int*)pfData)[7] = _tex2;
696 pfData += 8;
697
698 bounds.addVert(x2+xo, y2+yo, z2+zo);
699 pfData[0] = (x2 + xo);
700 pfData[1] = (y2 + yo);
701 pfData[2] = (z2 + zo);
702 pfData[3] = u2;
703 pfData[4] = v2;
704 ((int*)pfData)[5] = col1;
705 ((int*)pfData)[7] = _tex2;
706 pfData += 8;
707
708 bounds.addVert(x3+xo, y3+yo, z3+zo);
709 pfData[0] = (x3 + xo);
710 pfData[1] = (y3 + yo);
711 pfData[2] = (z3 + zo);
712 pfData[3] = u3;
713 pfData[4] = v3;
714 ((int*)pfData)[5] = col1;
715 ((int*)pfData)[7] = _tex2;
716 pfData += 8;
717
718 bounds.addVert(x4+xo, y4+yo, z4+zo);
719 pfData[0] = (x4 + xo);
720 pfData[1] = (y4 + yo);
721 pfData[2] = (z4 + zo);
722 pfData[3] = u4;
723 pfData[4] = v4;
724 ((int*)pfData)[5] = col1;
725 ((int*)pfData)[7] = _tex2;
726 pfData += 8;
727
728 if (vertices % 4 == 0 && p >= size - 8 * 4)
729 {
730 end();
731 tesselating = true;
732 }
733}
734#endif
735
736typedef unsigned short hfloat;
737extern hfloat convertFloatToHFloat(float f);
738extern float convertHFloatToFloat(hfloat hf);
739
740void Tesselator::vertex(float x, float y, float z)
741{
742 bounds.addVert(x+xo, y+yo, z+zo); // 4J MGH - added
743 count++;
744
745 // Signal to pixel shader whether to use mipmapping or not, by putting u into > 1 range if it is to be disabled
746 float uu = mipmapEnable ? u : (u + 1.0f);
747
748 // 4J - this format added for 360 to keep memory size of tesselated tiles down -
749 // see comments in packCompactQuad() for exact format
750 if( useCompactFormat360 )
751 {
752 unsigned int ucol = (unsigned int)col;
753
754#ifdef _XBOX
755 // Pack as 4:4:4 RGB_
756 unsigned short packedcol = (((col & 0xf0000000 ) >> 16 ) |
757 ((col & 0x00f00000 ) >> 12 ) |
758 ((col & 0x0000f000 ) >> 8 ));
759 int ipackedcol = ((int)packedcol) & 0xffff; // 0 to 65535 range
760
761 int quadIdx = vertices % 4;
762 m_ix[ quadIdx ] = (unsigned int)((x + xo) * 128.0f);
763 m_iy[ quadIdx ] = (unsigned int)((y + yo) * 128.0f);
764 m_iz[ quadIdx ] = (unsigned int)((z + zo) * 128.0f);
765 m_clr[ quadIdx ] = (unsigned int)ipackedcol;
766 m_u[ quadIdx ] = (int)(uu * 4096.0f);
767 m_v[ quadIdx ] = (int)(v * 4096.0f);
768 m_t2[ quadIdx ] = ( ( _tex2 & 0x00f00000 ) >> 20 ) | ( _tex2 & 0x000000f0 );
769 if( quadIdx == 3 )
770 {
771 packCompactQuad();
772 }
773#else
774 unsigned short packedcol = ((col & 0xf8000000 ) >> 16 ) |
775 ((col & 0x00fc0000 ) >> 13 ) |
776 ((col & 0x0000f800 ) >> 11 );
777 int ipackedcol = ((int)packedcol) & 0xffff; // 0 to 65535 range
778
779 ipackedcol -= 32768; // -32768 to 32767 range
780 ipackedcol &= 0xffff;
781
782#ifdef __PSVITA__
783 // AP - alpha cut out is expensive on vita. This will choose the correct data buffer depending on cut out enabled
784 int16_t* pShortData;
785 if( !alphaCutOutEnabled )
786 {
787 pShortData = (int16_t*)&_array->data[p];
788 }
789 else
790 {
791 pShortData = (int16_t*)&_array2->data[p2];
792 }
793#else
794 int16_t* pShortData = (int16_t*)&_array->data[p];
795
796#endif
797
798
799
800#ifdef __PS3__
801 float tex2U = ((int16_t*)&_tex2)[1] + 8;
802 float tex2V = ((int16_t*)&_tex2)[0] + 8;
803 float colVal1 = ((col&0xff000000)>>24)/256.0f;
804 float colVal2 = ((col&0x00ff0000)>>16)/256.0f;
805 float colVal3 = ((col&0x0000ff00)>>8)/256.0f;
806
807// pShortData[0] = convertFloatToHFloat(x + xo);
808// pShortData[1] = convertFloatToHFloat(y + yo);
809// pShortData[2] = convertFloatToHFloat(z + zo);
810// pShortData[3] = convertFloatToHFloat(uu);
811// pShortData[4] = convertFloatToHFloat(tex2U + colVal1);
812// pShortData[5] = convertFloatToHFloat(tex2V + colVal2);
813// pShortData[6] = convertFloatToHFloat(colVal3);
814// pShortData[7] = convertFloatToHFloat(v);
815
816 pShortData[0] = (((int)((x + xo ) * 1024.0f))&0xffff);
817 pShortData[1] = (((int)((y + yo ) * 1024.0f))&0xffff);
818 pShortData[2] = (((int)((z + zo ) * 1024.0f))&0xffff);
819 pShortData[3] = ipackedcol;
820 pShortData[4] = (((int)(uu * 8192.0f))&0xffff);
821 pShortData[5] = (((int)(v * 8192.0f))&0xffff);
822 pShortData[6] = (((int)(tex2U * (8192.0f/256.0f)))&0xffff);
823 pShortData[7] = (((int)(tex2V * (8192.0f/256.0f)))&0xffff);
824
825 p += 4;
826#else
827 pShortData[0] = (((int)((x + xo ) * 1024.0f))&0xffff);
828 pShortData[1] = (((int)((y + yo ) * 1024.0f))&0xffff);
829 pShortData[2] = (((int)((z + zo ) * 1024.0f))&0xffff);
830 pShortData[3] = ipackedcol;
831 pShortData[4] = (((int)(uu * 8192.0f))&0xffff);
832 pShortData[5] = (((int)(v * 8192.0f))&0xffff);
833 int16_t u2 = ((int16_t*)&_tex2)[0];
834 int16_t v2 = ((int16_t*)&_tex2)[1];
835#if defined _XBOX_ONE || defined __ORBIS__
836 // Optimisation - pack the second UVs into a single short (they could actually go in a byte), which frees up a short to store the x offset for this chunk in the vertex itself.
837 // This means that when rendering chunks, we don't need to update the vertex constants that specify the location for a chunk, when only the x offset has changed.
838 pShortData[6] = ( u2 << 8 ) | v2;
839 pShortData[7] = -xoo;
840#else
841 pShortData[6] = u2;
842 pShortData[7] = v2;
843#endif
844
845#ifdef __PSVITA__
846 // AP - alpha cut out is expensive on vita. This will choose the correct data buffer depending on cut out enabled
847 if( !alphaCutOutEnabled )
848 {
849 p += 4;
850 }
851 else
852 {
853 p2 += 4;
854 }
855#else
856 p += 4;
857#endif
858
859#endif
860
861#endif
862
863#ifdef __PSVITA__
864 // AP - alpha cut out is expensive on vita. Increase the correct vertices depending on cut out enabled
865 if( !alphaCutOutEnabled )
866 {
867 vertices++;
868 }
869 else
870 {
871 vertices2++;
872 }
873#else
874
875 vertices++;
876#endif
877
878#ifdef _XBOX
879 if (vertices % 4 == 0 && ( ( p >= size - 8 * 2 ) || ( ( p / 2 ) >= 65532 ) ) ) // Max 65535 verts in D3D, so 65532 is the last point at the end of a quad to catch it
880#else
881
882#ifdef __PSVITA__
883 // Max 65535 verts in D3D, so 65532 is the last point at the end of a quad to catch it
884 if ( (!alphaCutOutEnabled && vertices % 4 == 0 && ( ( p >= size - 4 * 4 ) || ( ( p / 4 ) >= 65532 ) )) ||
885 (alphaCutOutEnabled && vertices2 % 4 == 0 && ( ( p2 >= size - 4 * 4 ) || ( ( p2 / 4 ) >= 65532 ) )) )
886#else
887
888 if (vertices % 4 == 0 && ( ( p >= size - 4 * 4 ) || ( ( p / 4 ) >= 65532 ) ) ) // Max 65535 verts in D3D, so 65532 is the last point at the end of a quad to catch it
889#endif
890
891#endif
892 {
893 end();
894 tesselating = true;
895 }
896 }
897 else
898 {
899 if (mode == GL_QUADS && TRIANGLE_MODE && count % 4 == 0)
900 {
901 for (int i = 0; i < 2; i++)
902 {
903 int offs = 8 * (3 - i);
904 if (hasTexture)
905 {
906 _array->data[p + 3] = _array->data[p - offs + 3];
907 _array->data[p + 4] = _array->data[p - offs + 4];
908 }
909 if (hasColor)
910 {
911 _array->data[p + 5] = _array->data[p - offs + 5];
912 }
913
914 _array->data[p + 0] = _array->data[p - offs + 0];
915 _array->data[p + 1] = _array->data[p - offs + 1];
916 _array->data[p + 2] = _array->data[p - offs + 2];
917
918 vertices++;
919 p += 8;
920 }
921 }
922
923 if (hasTexture)
924 {
925 float *fdata = (float *)(_array->data + p + 3);
926 *fdata++ = uu;
927 *fdata++ = v;
928 }
929 if (hasColor)
930 {
931 _array->data[p + 5] = col;
932 }
933 if (hasNormal)
934 {
935 _array->data[p + 6] = _normal;
936 }
937 if (hasTexture2)
938 {
939#ifdef _XBOX
940 _array->data[p + 7] = ( ( _tex2 >> 16 ) & 0xffff ) | ( _tex2 << 16 );
941#else
942 #ifdef __PS3__
943 int16_t tex2U = ((int16_t*)&_tex2)[1] + 8;
944 int16_t tex2V = ((int16_t*)&_tex2)[0] + 8;
945 int16_t* pShortArray = (int16_t*)&_array->data[p + 7];
946 pShortArray[0] = tex2U;
947 pShortArray[1] = tex2V;
948 #else
949 _array->data[p + 7] = _tex2;
950 #endif
951#endif
952 }
953 else
954 {
955 // -512 each for u/v will mean that the renderer will use global settings (set via
956 // RenderManager.StateSetVertexTextureUV) rather than these local ones
957 *(unsigned int *)(&_array->data[p + 7]) = 0xfe00fe00;
958 }
959
960 float *fdata = (float *)(_array->data + p);
961 *fdata++ = (x + xo);
962 *fdata++ = (y + yo);
963 *fdata++ = (z + zo);
964 p += 8;
965
966 vertices++;
967 if (vertices % 4 == 0 && p >= size - 8 * 4)
968 {
969 end();
970 tesselating = true;
971 }
972 }
973}
974
975void Tesselator::color(int c)
976{
977 int r = ((c >> 16) & 255);
978 int g = ((c >> 8) & 255);
979 int b = ((c) & 255);
980 color(r, g, b);
981}
982
983void Tesselator::color(int c, int alpha)
984{
985 int r = ((c >> 16) & 255);
986 int g = ((c >> 8) & 255);
987 int b = ((c) & 255);
988 color(r, g, b, alpha);
989}
990
991void Tesselator::noColor()
992{
993 _noColor = true;
994}
995
996#ifdef __PS3__
997uint32_t _ConvertF32toX11Y11Z10N(float x, float y, float z)
998{
999 // 11111111111 X 0x000007FF
1000 // 1111111111100000000000 Y 0x003FF800
1001 // 11111111110000000000000000000000 Z 0xFFC00000
1002 // ZZZZZZZZZZYYYYYYYYYYYXXXXXXXXXXX
1003 // #defines for X11Y11Z10N format
1004#define X11Y11Z10N_X_MASK 0x000007FF
1005#define X11Y11Z10N_X_BITS 11
1006#define X11Y11Z10N_X_SHIFT 0
1007
1008#define X11Y11Z10N_Y_MASK 0x003FF800
1009#define X11Y11Z10N_Y_BITS 11
1010#define X11Y11Z10N_Y_SHIFT 11
1011
1012#define X11Y11Z10N_Z_MASK 0xFFC00000
1013#define X11Y11Z10N_Z_BITS 10
1014#define X11Y11Z10N_Z_SHIFT 22
1015
1016#ifndef _CONTENT_PACKAGE
1017 if (x<-1.0f || x>1.0f) { printf("Value (%5.3f) should be in range [-1..1]. Conversion will clamp to X11Y11Z10N.\n", x); }
1018 if (y<-1.0f || y>1.0f) { printf("Value (%5.3f) should be in range [-1..1]. Conversion will clamp to X11Y11Z10N.\n", y); }
1019 if (z<-1.0f || z>1.0f) { printf("Value (%5.3f) should be in range [-1..1]. Conversion will clamp to X11Y11Z10N.\n", z); }
1020#endif
1021
1022 const uint32_t uX = ((int32_t(max(min(((x)*2047.f - 1.f)*0.5f, 1023.f), -1024.f)) & (X11Y11Z10N_X_MASK >> X11Y11Z10N_X_SHIFT)) << X11Y11Z10N_X_SHIFT);
1023 const uint32_t uY = ((int32_t(max(min(((y)*2047.f - 1.f)*0.5f, 1023.f), -1024.f)) & (X11Y11Z10N_Y_MASK >> X11Y11Z10N_Y_SHIFT)) << X11Y11Z10N_Y_SHIFT);
1024 const uint32_t uZ = ((int32_t(max(min(((z)*1023.f - 1.f)*0.5f, 511.f), -512.f )) & (X11Y11Z10N_Z_MASK >> X11Y11Z10N_Z_SHIFT)) << X11Y11Z10N_Z_SHIFT);
1025 const uint32_t xyz = uX | uY | uZ;
1026 return xyz;
1027}
1028#endif // __PS3__
1029
1030void Tesselator::normal(float x, float y, float z)
1031{
1032 hasNormal = true;
1033
1034#ifdef __PS3__
1035 _normal = _ConvertF32toX11Y11Z10N(x,y,z);
1036#elif __PSVITA__
1037 // AP - casting a negative value to 'byte' on Vita results in zero. changed to a signed 8 value
1038 int8_t xx = (int8_t) (x * 127);
1039 int8_t yy = (int8_t) (y * 127);
1040 int8_t zz = (int8_t) (z * 127);
1041 _normal = (xx & 0xff) | ((yy & 0xff) << 8) | ((zz & 0xff) << 16);
1042#else
1043 byte xx = (byte) (x * 127);
1044 byte yy = (byte) (y * 127);
1045 byte zz = (byte) (z * 127);
1046 _normal = (xx & 0xff) | ((yy & 0xff) << 8) | ((zz & 0xff) << 16);
1047#endif
1048}
1049
1050void Tesselator::offset(float xo, float yo, float zo)
1051{
1052 this->xo = xo;
1053 this->yo = yo;
1054 this->zo = zo;
1055
1056 // 4J added
1057 this->xoo = xo;
1058 this->yoo = yo;
1059 this->zoo = zo;
1060}
1061
1062void Tesselator::addOffset(float x, float y, float z)
1063{
1064 xo += x;
1065 yo += y;
1066 zo += z;
1067}
1068
1069bool Tesselator::hasMaxVertices()
1070{
1071#ifdef __ORBIS__
1072 // On PS4, the way we push data to the command buffer has a maximum size of a single command packet of 2^16 bytes,
1073 // and the effective maximum size will be slightly less than that due to packet headers and padding.
1074 int bytes = vertices * (useCompactFormat360?16:32);
1075
1076 return bytes > 60 * 1024;
1077#else
1078 return false;
1079#endif
1080}