2013-08-23 00:26:16 +02:00
// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2014-03-29 16:51:38 -07:00
# include "GPU/GLES/TransformPipeline.h"
2013-09-24 11:14:04 +02:00
# include "Core/Config.h"
2013-08-23 00:26:16 +02:00
# include "Core/MemMap.h"
2013-09-21 23:37:14 +02:00
# include "GPU/Math3D.h"
2013-09-24 14:13:13 +02:00
# include "GPU/Common/SplineCommon.h"
2014-09-10 10:44:22 +02:00
# include "GPU/Common/VertexDecoderCommon.h"
2013-09-21 23:37:14 +02:00
2013-09-23 22:46:06 +02:00
// Here's how to evaluate them fast:
// http://and-what-happened.blogspot.se/2012/07/evaluating-b-splines-aka-basis-splines.html
2013-12-29 13:32:55 -08:00
u32 TransformDrawEngine : : NormalizeVertices ( u8 * outPtr , u8 * bufPtr , const u8 * inPtr , int lowerBound , int upperBound , u32 vertType ) {
2014-06-29 15:45:11 -07:00
const u32 vertTypeID = ( vertType & 0xFFFFFF ) | ( gstate . getUVGenMode ( ) < < 24 ) ;
VertexDecoder * dec = GetVertexDecoder ( vertTypeID ) ;
2014-09-18 00:45:11 +02:00
return DrawEngineCommon : : NormalizeVertices ( outPtr , bufPtr , inPtr , dec , lowerBound , upperBound , vertType ) ;
2013-12-29 13:32:55 -08:00
}
2013-09-22 09:51:32 +02:00
void TransformDrawEngine : : SubmitSpline ( void * control_points , void * indices , int count_u , int count_v , int type_u , int type_v , GEPatchPrimType prim_type , u32 vertType ) {
2013-08-23 00:26:16 +02:00
Flush ( ) ;
if ( prim_type ! = GE_PATCHPRIM_TRIANGLES ) {
// Only triangles supported!
return ;
}
u16 index_lower_bound = 0 ;
u16 index_upper_bound = count_u * count_v - 1 ;
2013-09-22 09:51:32 +02:00
bool indices_16bit = ( vertType & GE_VTYPE_IDX_MASK ) = = GE_VTYPE_IDX_16BIT ;
const u8 * indices8 = ( const u8 * ) indices ;
const u16 * indices16 = ( const u16 * ) indices ;
2013-08-23 00:26:16 +02:00
if ( indices )
2013-09-22 09:51:32 +02:00
GetIndexBounds ( indices , count_u * count_v , vertType , & index_lower_bound , & index_upper_bound ) ;
2013-08-23 00:26:16 +02:00
2013-09-21 23:37:14 +02:00
// Simplify away bones and morph before proceeding
SimpleVertex * simplified_control_points = ( SimpleVertex * ) ( decoded + 65536 * 12 ) ;
u8 * temp_buffer = decoded + 65536 * 24 ;
2013-09-22 10:50:33 +02:00
u32 origVertType = vertType ;
2013-09-22 09:51:32 +02:00
vertType = NormalizeVertices ( ( u8 * ) simplified_control_points , temp_buffer , ( u8 * ) control_points , index_lower_bound , index_upper_bound , vertType ) ;
2013-09-21 23:37:14 +02:00
2013-09-22 09:51:32 +02:00
VertexDecoder * vdecoder = GetVertexDecoder ( vertType ) ;
2013-09-21 23:37:14 +02:00
int vertexSize = vdecoder - > VertexSize ( ) ;
if ( vertexSize ! = sizeof ( SimpleVertex ) ) {
2013-09-25 18:50:09 +02:00
ERROR_LOG ( G3D , " Something went really wrong, vertex size: %i vs %i " , vertexSize , ( int ) sizeof ( SimpleVertex ) ) ;
2013-09-21 23:37:14 +02:00
}
const DecVtxFormat & vtxfmt = vdecoder - > GetDecVtxFmt ( ) ;
2013-08-23 00:26:16 +02:00
// TODO: Do something less idiotic to manage this buffer
2013-09-23 18:33:13 +02:00
SimpleVertex * * points = new SimpleVertex * [ count_u * count_v ] ;
// Make an array of pointers to the control points, to get rid of indices.
for ( int idx = 0 ; idx < count_u * count_v ; idx + + ) {
if ( indices )
points [ idx ] = simplified_control_points + ( indices_16bit ? indices16 [ idx ] : indices8 [ idx ] ) ;
else
points [ idx ] = simplified_control_points + idx ;
2013-08-23 00:26:16 +02:00
}
2013-09-21 23:37:14 +02:00
u8 * decoded2 = decoded + 65536 * 36 ;
2013-08-23 00:26:16 +02:00
int count = 0 ;
u8 * dest = decoded2 ;
2014-06-24 01:14:32 +02:00
SplinePatchLocal patch ;
2013-09-23 18:33:13 +02:00
patch . type_u = type_u ;
patch . type_v = type_v ;
patch . count_u = count_u ;
patch . count_v = count_v ;
patch . points = points ;
TesselateSplinePatch ( dest , count , patch , origVertType ) ;
delete [ ] points ;
2013-08-23 00:26:16 +02:00
2013-09-24 11:14:04 +02:00
u32 vertTypeWithIndex16 = ( vertType & ~ GE_VTYPE_IDX_MASK ) | GE_VTYPE_IDX_16BIT ;
2013-08-23 00:26:16 +02:00
2013-12-04 14:33:45 +01:00
UVScale prevUVScale ;
if ( g_Config . bPrescaleUV ) {
// We scaled during Normalize already so let's turn it off when drawing.
prevUVScale = gstate_c . uv ;
gstate_c . uv . uScale = 1.0f ;
gstate_c . uv . vScale = 1.0f ;
gstate_c . uv . uOff = 0 ;
gstate_c . uv . vOff = 0 ;
}
2013-11-14 14:03:03 +01:00
SubmitPrim ( decoded2 , quadIndices_ , GE_PRIM_TRIANGLES , count , vertTypeWithIndex16 , 0 ) ;
2013-12-04 14:33:45 +01:00
2013-08-23 00:26:16 +02:00
Flush ( ) ;
2013-12-04 14:33:45 +01:00
if ( g_Config . bPrescaleUV ) {
gstate_c . uv = prevUVScale ;
}
2013-08-29 23:19:38 +08:00
}
2013-08-30 10:25:01 +02:00
2013-09-22 09:51:32 +02:00
void TransformDrawEngine : : SubmitBezier ( void * control_points , void * indices , int count_u , int count_v , GEPatchPrimType prim_type , u32 vertType ) {
Flush ( ) ;
2013-08-30 10:25:01 +02:00
if ( prim_type ! = GE_PATCHPRIM_TRIANGLES ) {
// Only triangles supported!
return ;
}
2013-09-22 09:51:32 +02:00
u16 index_lower_bound = 0 ;
u16 index_upper_bound = count_u * count_v - 1 ;
bool indices_16bit = ( vertType & GE_VTYPE_IDX_MASK ) = = GE_VTYPE_IDX_16BIT ;
const u8 * indices8 = ( const u8 * ) indices ;
const u16 * indices16 = ( const u16 * ) indices ;
if ( indices )
GetIndexBounds ( indices , count_u * count_v , vertType , & index_lower_bound , & index_upper_bound ) ;
// Simplify away bones and morph before proceeding
SimpleVertex * simplified_control_points = ( SimpleVertex * ) ( decoded + 65536 * 12 ) ;
u8 * temp_buffer = decoded + 65536 * 24 ;
2013-09-22 10:50:33 +02:00
u32 origVertType = vertType ;
2013-09-22 09:51:32 +02:00
vertType = NormalizeVertices ( ( u8 * ) simplified_control_points , temp_buffer , ( u8 * ) control_points , index_lower_bound , index_upper_bound , vertType ) ;
VertexDecoder * vdecoder = GetVertexDecoder ( vertType ) ;
2013-08-30 10:25:01 +02:00
2013-09-22 09:51:32 +02:00
int vertexSize = vdecoder - > VertexSize ( ) ;
if ( vertexSize ! = sizeof ( SimpleVertex ) ) {
2013-09-25 18:50:09 +02:00
ERROR_LOG ( G3D , " Something went really wrong, vertex size: %i vs %i " , vertexSize , ( int ) sizeof ( SimpleVertex ) ) ;
2013-09-22 09:51:32 +02:00
}
const DecVtxFormat & vtxfmt = vdecoder - > GetDecVtxFmt ( ) ;
// Bezier patches share less control points than spline patches. Otherwise they are pretty much the same (except bezier don't support the open/close thing)
int num_patches_u = ( count_u - 1 ) / 3 ;
int num_patches_v = ( count_v - 1 ) / 3 ;
2013-09-23 18:33:13 +02:00
BezierPatch * patches = new BezierPatch [ num_patches_u * num_patches_v ] ;
2013-09-22 09:51:32 +02:00
for ( int patch_u = 0 ; patch_u < num_patches_u ; patch_u + + ) {
for ( int patch_v = 0 ; patch_v < num_patches_v ; patch_v + + ) {
2013-09-23 18:33:13 +02:00
BezierPatch & patch = patches [ patch_u + patch_v * num_patches_u ] ;
2013-09-22 09:51:32 +02:00
for ( int point = 0 ; point < 16 ; + + point ) {
int idx = ( patch_u * 3 + point % 4 ) + ( patch_v * 3 + point / 4 ) * count_u ;
if ( indices )
patch . points [ point ] = simplified_control_points + ( indices_16bit ? indices16 [ idx ] : indices8 [ idx ] ) ;
else
patch . points [ point ] = simplified_control_points + idx ;
}
patch . u_index = patch_u * 3 ;
patch . v_index = patch_v * 3 ;
}
}
u8 * decoded2 = decoded + 65536 * 36 ;
int count = 0 ;
u8 * dest = decoded2 ;
2013-10-10 17:36:42 +02:00
// Simple approximation of the real tesselation factor.
// We shouldn't really split up into separate 4x4 patches, instead we should do something that works
// like the splines, so we subdivide across the whole "mega-patch".
2014-01-23 05:45:28 +08:00
if ( num_patches_u = = 0 ) num_patches_u = 1 ;
if ( num_patches_v = = 0 ) num_patches_v = 1 ;
2013-10-10 17:36:42 +02:00
int tess_u = gstate . getPatchDivisionU ( ) / num_patches_u ;
int tess_v = gstate . getPatchDivisionV ( ) / num_patches_v ;
if ( tess_u < 4 ) tess_u = 4 ;
if ( tess_v < 4 ) tess_v = 4 ;
2013-09-22 09:51:32 +02:00
for ( int patch_idx = 0 ; patch_idx < num_patches_u * num_patches_v ; + + patch_idx ) {
2013-09-23 18:33:13 +02:00
BezierPatch & patch = patches [ patch_idx ] ;
2013-10-10 17:36:42 +02:00
TesselateBezierPatch ( dest , count , tess_u , tess_v , patch , origVertType ) ;
2013-09-22 09:51:32 +02:00
}
delete [ ] patches ;
2013-09-24 11:14:04 +02:00
u32 vertTypeWithIndex16 = ( vertType & ~ GE_VTYPE_IDX_MASK ) | GE_VTYPE_IDX_16BIT ;
2013-09-22 09:51:32 +02:00
2013-12-04 14:33:45 +01:00
UVScale prevUVScale ;
if ( g_Config . bPrescaleUV ) {
// We scaled during Normalize already so let's turn it off when drawing.
prevUVScale = gstate_c . uv ;
gstate_c . uv . uScale = 1.0f ;
gstate_c . uv . vScale = 1.0f ;
gstate_c . uv . uOff = 0 ;
gstate_c . uv . vOff = 0 ;
}
2013-11-14 14:03:03 +01:00
SubmitPrim ( decoded2 , quadIndices_ , GE_PRIM_TRIANGLES , count , vertTypeWithIndex16 , 0 ) ;
2013-08-30 10:25:01 +02:00
Flush ( ) ;
2013-12-04 14:33:45 +01:00
if ( g_Config . bPrescaleUV ) {
gstate_c . uv = prevUVScale ;
}
2013-08-30 10:25:01 +02:00
}