2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00:00
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 ; either version 2
of the License , or ( at your option ) any later version .
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 for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// gl_mesh.c: triangle model functions
# include "quakedef.h"
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ALIAS MODEL DISPLAY LIST GENERATION
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
# define countof(x) (sizeof(x) / sizeof((x)[0]))
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = =
GL_MakeAliasModelDisplayLists
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
Saves data needed to build the VBO for this model on the hunk . Afterwards this
is copied to Mod_Extradata .
Original code by MH from RMQEngine
= = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
void GL_MakeAliasModelDisplayLists ( qmodel_t * m , aliashdr_t * paliashdr )
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
int i , j ;
int maxverts_vbo ;
unsigned short * indexes ;
2017-09-17 02:12:53 +00:00
trivertx_t * verts ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
aliasmesh_t * desc ;
// there can never be more than this number of verts and we just put them all on the hunk
2017-09-17 02:12:53 +00:00
// front/back logic says we can never have more than numverts*2
maxverts_vbo = paliashdr - > numverts * 2 ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
desc = ( aliasmesh_t * ) Hunk_Alloc ( sizeof ( aliasmesh_t ) * maxverts_vbo ) ;
// there will always be this number of indexes
2017-09-17 02:12:53 +00:00
indexes = ( unsigned short * ) Hunk_Alloc ( sizeof ( unsigned short ) * paliashdr - > numtris * 3 ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
paliashdr - > indexes = ( intptr_t ) indexes - ( intptr_t ) paliashdr ;
paliashdr - > meshdesc = ( intptr_t ) desc - ( intptr_t ) paliashdr ;
paliashdr - > numindexes = 0 ;
paliashdr - > numverts_vbo = 0 ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
for ( i = 0 ; i < paliashdr - > numtris ; i + + )
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
for ( j = 0 ; j < 3 ; j + + )
{
int v ;
// index into hdr->vertexes
unsigned short vertindex = triangles [ i ] . vertindex [ j ] ;
// basic s/t coords
int s = stverts [ vertindex ] . s ;
int t = stverts [ vertindex ] . t ;
// check for back side and adjust texcoord s
2017-09-17 02:12:53 +00:00
if ( ! triangles [ i ] . facesfront & & stverts [ vertindex ] . onseam ) s + = paliashdr - > skinwidth / 2 ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
// see does this vert already exist
2017-09-17 02:12:53 +00:00
for ( v = 0 ; v < paliashdr - > numverts_vbo ; v + + )
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
// it could use the same xyz but have different s and t
if ( desc [ v ] . vertindex = = vertindex & & ( int ) desc [ v ] . st [ 0 ] = = s & & ( int ) desc [ v ] . st [ 1 ] = = t )
{
// exists; emit an index for it
2017-09-17 02:12:53 +00:00
indexes [ paliashdr - > numindexes + + ] = v ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
// no need to check any more
break ;
}
}
2017-09-17 02:12:53 +00:00
if ( v = = paliashdr - > numverts_vbo )
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
// doesn't exist; emit a new vert and index
2017-09-17 02:12:53 +00:00
indexes [ paliashdr - > numindexes + + ] = paliashdr - > numverts_vbo ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
desc [ paliashdr - > numverts_vbo ] . vertindex = vertindex ;
desc [ paliashdr - > numverts_vbo ] . st [ 0 ] = s ;
desc [ paliashdr - > numverts_vbo + + ] . st [ 1 ] = t ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
}
}
}
2017-09-17 02:12:53 +00:00
2019-01-30 01:54:49 +00:00
switch ( paliashdr - > poseverttype )
{
case PV_QUAKEFORGE :
2019-11-02 15:50:53 +00:00
verts = ( trivertx_t * ) Hunk_Alloc ( paliashdr - > nummorphposes * paliashdr - > numverts_vbo * 2 * sizeof ( * verts ) ) ;
2019-01-30 01:54:49 +00:00
paliashdr - > vertexes = ( byte * ) verts - ( byte * ) paliashdr ;
2019-11-02 15:50:53 +00:00
for ( i = 0 ; i < paliashdr - > nummorphposes ; i + + )
2019-01-30 01:54:49 +00:00
for ( j = 0 ; j < paliashdr - > numverts_vbo ; j + + )
{
verts [ i * paliashdr - > numverts_vbo * 2 + j ] = poseverts_mdl [ i ] [ desc [ j ] . vertindex ] ;
verts [ i * paliashdr - > numverts_vbo * 2 + j + paliashdr - > numverts_vbo ] = poseverts_mdl [ i ] [ desc [ j ] . vertindex + paliashdr - > numverts_vbo ] ;
}
break ;
case PV_QUAKE1 :
2019-11-02 15:50:53 +00:00
verts = ( trivertx_t * ) Hunk_Alloc ( paliashdr - > nummorphposes * paliashdr - > numverts_vbo * sizeof ( * verts ) ) ;
2019-01-30 01:54:49 +00:00
paliashdr - > vertexes = ( byte * ) verts - ( byte * ) paliashdr ;
2019-11-02 15:50:53 +00:00
for ( i = 0 ; i < paliashdr - > nummorphposes ; i + + )
2019-01-30 01:54:49 +00:00
for ( j = 0 ; j < paliashdr - > numverts_vbo ; j + + )
verts [ i * paliashdr - > numverts_vbo + j ] = poseverts_mdl [ i ] [ desc [ j ] . vertindex ] ;
break ;
2019-11-02 15:50:53 +00:00
case PV_IQM :
2019-01-30 01:54:49 +00:00
case PV_QUAKE3 :
break ; //invalid here.
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
}
# define NUMVERTEXNORMALS 162
extern float r_avertexnormals [ NUMVERTEXNORMALS ] [ 3 ] ;
/*
= = = = = = = = = = = = = = = =
2015-09-20 20:10:49 +00:00
GLMesh_LoadVertexBuffer
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
Upload the given alias model ' s mesh to a VBO
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
Original code by MH from RMQEngine
2017-09-17 02:12:53 +00:00
may update the mesh vbo / ebo offsets .
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
= = = = = = = = = = = = = = = =
*/
2017-09-17 02:12:53 +00:00
void GLMesh_LoadVertexBuffer ( qmodel_t * m , aliashdr_t * mainhdr )
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
2017-09-17 02:12:53 +00:00
//we always need vertex array data.
//if we don't support vbos(gles?) then we just use system memory.
//if we're not using glsl(gles1?), then we don't actually need all the data, but we do still need some so its easier to just alloc the lot.
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
int totalvbosize = 0 ;
2015-09-20 20:10:49 +00:00
const aliasmesh_t * desc ;
2017-09-17 02:12:53 +00:00
const void * trivertexes ;
byte * ebodata ;
2015-09-20 20:10:49 +00:00
byte * vbodata ;
int f ;
2017-09-17 02:12:53 +00:00
aliashdr_t * hdr ;
unsigned int numindexes , numverts ;
intptr_t stofs ;
intptr_t vertofs ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
//count how much space we're going to need.
for ( hdr = mainhdr , numverts = 0 , numindexes = 0 ; ; )
{
2019-01-30 01:54:49 +00:00
switch ( hdr - > poseverttype )
{
case PV_QUAKE1 :
2019-11-02 15:50:53 +00:00
totalvbosize + = ( hdr - > nummorphposes * hdr - > numverts_vbo * sizeof ( meshxyz_mdl_t ) ) ; // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
2019-01-30 01:54:49 +00:00
break ;
case PV_QUAKEFORGE :
2019-11-02 15:50:53 +00:00
totalvbosize + = ( hdr - > nummorphposes * hdr - > numverts_vbo * sizeof ( meshxyz_mdl16_t ) ) ;
2019-01-30 01:54:49 +00:00
break ;
case PV_QUAKE3 :
2019-11-02 15:50:53 +00:00
totalvbosize + = ( hdr - > nummorphposes * hdr - > numverts_vbo * sizeof ( meshxyz_md3_t ) ) ;
break ;
case PV_IQM :
totalvbosize + = ( hdr - > nummorphposes * hdr - > numverts_vbo * sizeof ( iqmvert_t ) ) ;
2019-01-30 01:54:49 +00:00
break ;
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
numverts + = hdr - > numverts_vbo ;
numindexes + = hdr - > numindexes ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
if ( hdr - > nextsurface )
hdr = ( aliashdr_t * ) ( ( byte * ) hdr + hdr - > nextsurface ) ;
else
break ;
}
hdr = NULL ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
vertofs = 0 ;
totalvbosize = ( totalvbosize + 7 ) & ~ 7 ; //align it.
stofs = totalvbosize ;
totalvbosize + = ( numverts * sizeof ( meshst_t ) ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
if ( ! totalvbosize ) return ;
if ( ! numindexes ) return ;
//create an elements buffer
ebodata = ( byte * ) malloc ( numindexes * sizeof ( unsigned short ) ) ;
if ( ! ebodata )
return ; //fatal
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
// create the vertex buffer (empty)
2015-09-20 20:10:49 +00:00
vbodata = ( byte * ) malloc ( totalvbosize ) ;
2017-09-17 02:12:53 +00:00
if ( ! vbodata )
{ //fatal
free ( ebodata ) ;
return ;
}
2015-09-20 20:10:49 +00:00
memset ( vbodata , 0 , totalvbosize ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
numindexes = 0 ;
for ( hdr = mainhdr , numverts = 0 , numindexes = 0 ; ; )
2015-09-20 20:10:49 +00:00
{
2017-09-17 02:12:53 +00:00
// grab the pointers to data in the extradata
desc = ( aliasmesh_t * ) ( ( byte * ) hdr + hdr - > meshdesc ) ;
trivertexes = ( void * ) ( ( byte * ) hdr + hdr - > vertexes ) ;
//submit the index data.
hdr - > eboofs = numindexes * sizeof ( unsigned short ) ;
numindexes + = hdr - > numindexes ;
memcpy ( ebodata + hdr - > eboofs , ( short * ) ( ( byte * ) hdr + hdr - > indexes ) , hdr - > numindexes * sizeof ( unsigned short ) ) ;
hdr - > vbovertofs = vertofs ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
// fill in the vertices at the start of the buffer
2019-01-30 01:54:49 +00:00
switch ( hdr - > poseverttype )
2015-09-20 20:10:49 +00:00
{
2019-01-30 01:54:49 +00:00
case PV_QUAKE1 :
2019-11-02 15:50:53 +00:00
for ( f = 0 ; f < hdr - > nummorphposes ; f + + ) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
2017-09-17 02:12:53 +00:00
{
int v ;
meshxyz_mdl_t * xyz = ( meshxyz_mdl_t * ) ( vbodata + vertofs ) ;
2019-11-02 15:50:53 +00:00
const trivertx_t * tv = ( const trivertx_t * ) trivertexes + ( hdr - > numverts_vbo * f ) ;
2017-09-17 02:12:53 +00:00
vertofs + = hdr - > numverts_vbo * sizeof ( * xyz ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
for ( v = 0 ; v < hdr - > numverts_vbo ; v + + , tv + + )
{
xyz [ v ] . xyz [ 0 ] = tv - > v [ 0 ] ;
xyz [ v ] . xyz [ 1 ] = tv - > v [ 1 ] ;
xyz [ v ] . xyz [ 2 ] = tv - > v [ 2 ] ;
xyz [ v ] . xyz [ 3 ] = 1 ; // need w 1 for 4 byte vertex compression
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
// this introduces some error (less than 0.004), but the normals were very coarse
// to begin with
xyz [ v ] . normal [ 0 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 0 ] ;
xyz [ v ] . normal [ 1 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 1 ] ;
xyz [ v ] . normal [ 2 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 2 ] ;
xyz [ v ] . normal [ 3 ] = 0 ; // unused; for 4-byte alignment
}
}
2019-01-30 01:54:49 +00:00
break ;
case PV_QUAKEFORGE :
2019-11-02 15:50:53 +00:00
for ( f = 0 ; f < hdr - > nummorphposes ; f + + ) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
2019-01-30 01:54:49 +00:00
{
int v ;
meshxyz_mdl16_t * xyz = ( meshxyz_mdl16_t * ) ( vbodata + vertofs ) ;
2019-11-02 15:50:53 +00:00
const trivertx_t * tv = ( const trivertx_t * ) trivertexes + ( hdr - > numverts_vbo * 2 * f ) ;
2019-01-30 01:54:49 +00:00
vertofs + = hdr - > numverts_vbo * sizeof ( * xyz ) ;
for ( v = 0 ; v < hdr - > numverts_vbo ; v + + , tv + + )
{
xyz [ v ] . xyz [ 0 ] = ( tv - > v [ 0 ] < < 8 ) | tv [ hdr - > numverts_vbo ] . v [ 0 ] ;
xyz [ v ] . xyz [ 1 ] = ( tv - > v [ 1 ] < < 8 ) | tv [ hdr - > numverts_vbo ] . v [ 0 ] ;
xyz [ v ] . xyz [ 2 ] = ( tv - > v [ 2 ] < < 8 ) | tv [ hdr - > numverts_vbo ] . v [ 0 ] ;
xyz [ v ] . xyz [ 3 ] = 1 ; // need w 1 for 4 byte vertex compression
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
// this introduces some error (less than 0.004), but the normals were very coarse
// to begin with
xyz [ v ] . normal [ 0 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 0 ] ;
xyz [ v ] . normal [ 1 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 1 ] ;
xyz [ v ] . normal [ 2 ] = 127 * r_avertexnormals [ tv - > lightnormalindex ] [ 2 ] ;
xyz [ v ] . normal [ 3 ] = 0 ; // unused; for 4-byte alignment
}
}
break ;
case PV_QUAKE3 :
2019-11-02 15:50:53 +00:00
for ( f = 0 ; f < hdr - > nummorphposes ; f + + ) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
2017-09-17 02:12:53 +00:00
{
int v ;
meshxyz_md3_t * xyz = ( meshxyz_md3_t * ) ( vbodata + vertofs ) ;
2019-11-02 15:50:53 +00:00
const md3XyzNormal_t * tv = ( const md3XyzNormal_t * ) trivertexes + ( hdr - > numverts_vbo * f ) ;
2017-09-17 02:12:53 +00:00
float lat , lng ;
vertofs + = hdr - > numverts_vbo * sizeof ( * xyz ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
for ( v = 0 ; v < hdr - > numverts_vbo ; v + + , tv + + )
{
xyz [ v ] . xyz [ 0 ] = tv - > xyz [ 0 ] ;
xyz [ v ] . xyz [ 1 ] = tv - > xyz [ 1 ] ;
xyz [ v ] . xyz [ 2 ] = tv - > xyz [ 2 ] ;
xyz [ v ] . xyz [ 3 ] = 1 ; // need w 1 for 4 byte vertex compression
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
// this introduces some error (less than 0.004), but the normals were very coarse
// to begin with
lat = ( float ) tv - > latlong [ 0 ] * ( 2 * M_PI ) * ( 1.0 / 255.0 ) ;
lng = ( float ) tv - > latlong [ 1 ] * ( 2 * M_PI ) * ( 1.0 / 255.0 ) ;
xyz [ v ] . normal [ 0 ] = 127 * cos ( lng ) * sin ( lat ) ;
xyz [ v ] . normal [ 1 ] = 127 * sin ( lng ) * sin ( lat ) ;
xyz [ v ] . normal [ 2 ] = 127 * cos ( lat ) ;
xyz [ v ] . normal [ 3 ] = 0 ; // unused; for 4-byte alignment
}
}
2019-01-30 01:54:49 +00:00
break ;
2019-11-02 15:50:53 +00:00
case PV_IQM :
for ( f = 0 ; f < hdr - > nummorphposes ; f + + ) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
{
int v ;
iqmvert_t * xyz = ( iqmvert_t * ) ( vbodata + vertofs ) ;
const iqmvert_t * tv = ( const iqmvert_t * ) trivertexes + ( hdr - > numverts_vbo * f ) ;
vertofs + = hdr - > numverts_vbo * sizeof ( * xyz ) ;
for ( v = 0 ; v < hdr - > numverts_vbo ; v + + , tv + + )
xyz [ v ] = * tv ;
}
break ;
2017-09-17 02:12:53 +00:00
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
// fill in the ST coords at the end of the buffer
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
{
2017-09-17 02:12:53 +00:00
meshst_t * st ;
float hscale , vscale ;
//johnfitz -- padded skins
hscale = ( float ) hdr - > skinwidth / ( float ) TexMgr_PadConditional ( hdr - > skinwidth ) ;
vscale = ( float ) hdr - > skinheight / ( float ) TexMgr_PadConditional ( hdr - > skinheight ) ;
//johnfitz
hdr - > vbostofs = stofs ;
st = ( meshst_t * ) ( vbodata + stofs ) ;
stofs + = hdr - > numverts_vbo * sizeof ( * st ) ;
2019-01-30 01:54:49 +00:00
switch ( hdr - > poseverttype )
2017-09-17 02:12:53 +00:00
{
2019-01-30 01:54:49 +00:00
case PV_QUAKE3 :
2017-09-17 02:12:53 +00:00
for ( f = 0 ; f < hdr - > numverts_vbo ; f + + )
{ //md3 has floating-point skin coords. use the values directly.
st [ f ] . st [ 0 ] = hscale * desc [ f ] . st [ 0 ] ;
st [ f ] . st [ 1 ] = vscale * desc [ f ] . st [ 1 ] ;
}
2019-01-30 01:54:49 +00:00
break ;
case PV_QUAKEFORGE :
case PV_QUAKE1 :
2017-09-17 02:12:53 +00:00
for ( f = 0 ; f < hdr - > numverts_vbo ; f + + )
{
st [ f ] . st [ 0 ] = hscale * ( ( float ) desc [ f ] . st [ 0 ] + 0.5f ) / ( float ) hdr - > skinwidth ;
st [ f ] . st [ 1 ] = vscale * ( ( float ) desc [ f ] . st [ 1 ] + 0.5f ) / ( float ) hdr - > skinheight ;
}
2019-01-30 01:54:49 +00:00
break ;
2019-11-02 15:50:53 +00:00
case PV_IQM :
//st coords are interleaved.
break ;
2017-09-17 02:12:53 +00:00
}
2015-09-20 20:10:49 +00:00
}
2017-09-17 02:12:53 +00:00
if ( hdr - > nextsurface )
hdr = ( aliashdr_t * ) ( ( byte * ) hdr + hdr - > nextsurface ) ;
else
break ;
2015-09-20 20:10:49 +00:00
}
2017-09-17 02:12:53 +00:00
hdr = NULL ;
if ( gl_vbo_able )
{
// upload indexes buffer
GL_DeleteBuffersFunc ( 1 , & m - > meshindexesvbo ) ;
GL_GenBuffersFunc ( 1 , & m - > meshindexesvbo ) ;
GL_BindBufferFunc ( GL_ELEMENT_ARRAY_BUFFER , m - > meshindexesvbo ) ;
GL_BufferDataFunc ( GL_ELEMENT_ARRAY_BUFFER , numindexes * sizeof ( unsigned short ) , ebodata , GL_STATIC_DRAW ) ;
// upload vertexes buffer
GL_DeleteBuffersFunc ( 1 , & m - > meshvbo ) ;
GL_GenBuffersFunc ( 1 , & m - > meshvbo ) ;
GL_BindBufferFunc ( GL_ARRAY_BUFFER , m - > meshvbo ) ;
GL_BufferDataFunc ( GL_ARRAY_BUFFER , totalvbosize , vbodata , GL_STATIC_DRAW ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
free ( vbodata ) ;
free ( ebodata ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
m - > meshvboptr = NULL ;
m - > meshindexesvboptr = NULL ;
}
else
{
m - > meshvboptr = vbodata ;
m - > meshindexesvboptr = ebodata ;
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
// invalidate the cached bindings
GL_ClearBufferBindings ( ) ;
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
/*
= = = = = = = = = = = = = = = =
GLMesh_LoadVertexBuffers
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
Loop over all precached alias models , and upload each one to a VBO .
= = = = = = = = = = = = = = = =
*/
void GLMesh_LoadVertexBuffers ( void )
{
int j ;
qmodel_t * m ;
2017-09-17 02:12:53 +00:00
aliashdr_t * hdr ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
for ( j = 1 ; j < MAX_MODELS ; j + + )
{
if ( ! ( m = cl . model_precache [ j ] ) ) break ;
if ( m - > type ! = mod_alias ) continue ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2017-09-17 02:12:53 +00:00
hdr = ( aliashdr_t * ) Mod_Extradata ( m ) ;
2015-09-20 20:10:49 +00:00
GLMesh_LoadVertexBuffer ( m , hdr ) ;
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
}
2015-09-20 20:10:49 +00:00
}
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
2015-09-20 20:10:49 +00:00
/*
= = = = = = = = = = = = = = = =
GLMesh_DeleteVertexBuffers
Delete VBOs for all loaded alias models
= = = = = = = = = = = = = = = =
*/
void GLMesh_DeleteVertexBuffers ( void )
{
int j ;
qmodel_t * m ;
2017-09-17 02:12:53 +00:00
if ( ! gl_vbo_able )
2015-09-20 20:10:49 +00:00
return ;
for ( j = 1 ; j < MAX_MODELS ; j + + )
{
if ( ! ( m = cl . model_precache [ j ] ) ) break ;
if ( m - > type ! = mod_alias ) continue ;
2017-09-17 02:12:53 +00:00
if ( m - > meshvbo )
GL_DeleteBuffersFunc ( 1 , & m - > meshvbo ) ;
2015-09-20 20:10:49 +00:00
m - > meshvbo = 0 ;
2017-09-17 02:12:53 +00:00
free ( m - > meshvboptr ) ;
m - > meshvboptr = NULL ;
2015-09-20 20:10:49 +00:00
2017-09-17 02:12:53 +00:00
if ( m - > meshindexesvbo )
GL_DeleteBuffersFunc ( 1 , & m - > meshindexesvbo ) ;
2015-09-20 20:10:49 +00:00
m - > meshindexesvbo = 0 ;
2017-09-17 02:12:53 +00:00
free ( m - > meshindexesvboptr ) ;
m - > meshindexesvboptr = NULL ;
2015-09-20 20:10:49 +00:00
}
2017-09-17 02:12:53 +00:00
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
GL_ClearBufferBindings ( ) ;
}
2017-09-17 02:12:53 +00:00
//from gl_model.c
extern char loadname [ ] ; // for hunk tags
void Mod_CalcAliasBounds ( aliashdr_t * a ) ;
# define MD3_VERSION 15
//structures from Tenebrae
typedef struct {
int ident ;
int version ;
char name [ 64 ] ;
int flags ; //assumed to match quake1 models, for lack of somewhere better.
int numFrames ;
int numTags ;
int numSurfaces ;
int numSkins ;
int ofsFrames ;
int ofsTags ;
int ofsSurfaces ;
int ofsEnd ;
} md3Header_t ;
//then has header->numFrames of these at header->ofs_Frames
typedef struct md3Frame_s {
vec3_t bounds [ 2 ] ;
vec3_t localOrigin ;
float radius ;
char name [ 16 ] ;
} md3Frame_t ;
//there are header->numSurfaces of these at header->ofsSurfaces, following from ofsEnd
typedef struct {
int ident ; //
char name [ 64 ] ; // polyset name
int flags ;
int numFrames ; // all surfaces in a model should have the same
int numShaders ; // all surfaces in a model should have the same
int numVerts ;
int numTriangles ;
int ofsTriangles ;
int ofsShaders ; // offset from start of md3Surface_t
int ofsSt ; // texture coords are common for all frames
int ofsXyzNormals ; // numVerts * numFrames
int ofsEnd ; // next surface follows
} md3Surface_t ;
//at surf+surf->ofsXyzNormals
/*typedef struct {
short xyz [ 3 ] ;
byte latlong [ 2 ] ;
} md3XyzNormal_t ; */
//surf->numTriangles at surf+surf->ofsTriangles
typedef struct {
int indexes [ 3 ] ;
} md3Triangle_t ;
//surf->numVerts at surf+surf->ofsSt
typedef struct {
float s ;
float t ;
} md3St_t ;
typedef struct {
char name [ 64 ] ;
int shaderIndex ;
} md3Shader_t ;
void Mod_LoadMD3Model ( qmodel_t * mod , void * buffer )
{
md3Header_t * pinheader ;
md3Surface_t * pinsurface ;
md3Frame_t * pinframes ;
md3Triangle_t * pintriangle ;
unsigned short * poutindexes ;
md3XyzNormal_t * pinvert ;
md3XyzNormal_t * poutvert ;
md3St_t * pinst ;
aliasmesh_t * poutst ;
md3Shader_t * pinshader ;
int size ;
int start , end , total ;
int ival , j ;
int numsurfs , surf ;
int numframes ;
aliashdr_t * outhdr ;
start = Hunk_LowMark ( ) ;
pinheader = ( md3Header_t * ) buffer ;
ival = LittleLong ( pinheader - > version ) ;
if ( ival ! = MD3_VERSION )
Sys_Error ( " %s has wrong version number (%i should be %i) " ,
mod - > name , ival , MD3_VERSION ) ;
numsurfs = LittleLong ( pinheader - > numSurfaces ) ;
numframes = LittleLong ( pinheader - > numFrames ) ;
if ( numframes > MAXALIASFRAMES )
Sys_Error ( " %s has too many frames (%i vs %i) " ,
mod - > name , numframes , MAXALIASFRAMES ) ;
if ( ! numsurfs )
Sys_Error ( " %s has nosurfaces " , mod - > name ) ;
pinframes = ( md3Frame_t * ) ( ( byte * ) buffer + LittleLong ( pinheader - > ofsFrames ) ) ;
//
// allocate space for a working header, plus all the data except the frames,
// skin and group info
//
size = sizeof ( aliashdr_t ) + ( numframes - 1 ) * sizeof ( outhdr - > frames [ 0 ] ) ;
outhdr = ( aliashdr_t * ) Hunk_AllocName ( size * numsurfs , loadname ) ;
for ( surf = 0 , pinsurface = ( md3Surface_t * ) ( ( byte * ) buffer + LittleLong ( pinheader - > ofsSurfaces ) ) ; surf < numsurfs ; surf + + , pinsurface = ( md3Surface_t * ) ( ( byte * ) pinsurface + LittleLong ( pinsurface - > ofsEnd ) ) )
{
aliashdr_t * osurf = ( aliashdr_t * ) ( ( byte * ) outhdr + size * surf ) ;
if ( LittleLong ( pinsurface - > ident ) ! = ( ( ' I ' < < 0 ) | ( ' D ' < < 8 ) | ( ' P ' < < 16 ) | ( ' 3 ' < < 24 ) ) )
Sys_Error ( " %s corrupt surface ident " , mod - > name ) ;
if ( LittleLong ( pinsurface - > numFrames ) ! = numframes )
Sys_Error ( " %s mismatched framecounts " , mod - > name ) ;
if ( surf + 1 < numsurfs )
osurf - > nextsurface = size ;
else
osurf - > nextsurface = 0 ;
2019-01-30 01:54:49 +00:00
osurf - > poseverttype = PV_QUAKE3 ;
2017-09-17 02:12:53 +00:00
osurf - > numverts_vbo = osurf - > numverts = LittleLong ( pinsurface - > numVerts ) ;
pinvert = ( md3XyzNormal_t * ) ( ( byte * ) pinsurface + LittleLong ( pinsurface - > ofsXyzNormals ) ) ;
poutvert = ( md3XyzNormal_t * ) Hunk_Alloc ( numframes * osurf - > numverts * sizeof ( * poutvert ) ) ;
osurf - > vertexes = ( byte * ) poutvert - ( byte * ) osurf ;
for ( ival = 0 ; ival < numframes ; ival + + )
{
osurf - > frames [ ival ] . firstpose = ival ;
osurf - > frames [ ival ] . numposes = 1 ;
osurf - > frames [ ival ] . interval = 0.1 ;
q_strlcpy ( osurf - > frames [ ival ] . name , pinframes - > name , sizeof ( osurf - > frames [ ival ] . name ) ) ;
for ( j = 0 ; j < 3 ; j + + )
{ //fixme...
osurf - > frames [ ival ] . bboxmin . v [ j ] = 0 ;
osurf - > frames [ ival ] . bboxmax . v [ j ] = 255 ;
}
for ( j = 0 ; j < osurf - > numverts ; j + + )
poutvert [ j ] = pinvert [ j ] ;
poutvert + = osurf - > numverts ;
pinvert + = osurf - > numverts ;
}
2019-11-02 15:50:53 +00:00
osurf - > nummorphposes = osurf - > numframes = numframes ;
2017-09-17 02:12:53 +00:00
osurf - > numtris = LittleLong ( pinsurface - > numTriangles ) ;
osurf - > numindexes = osurf - > numtris * 3 ;
pintriangle = ( md3Triangle_t * ) ( ( byte * ) pinsurface + LittleLong ( pinsurface - > ofsTriangles ) ) ;
poutindexes = ( unsigned short * ) Hunk_Alloc ( sizeof ( * poutindexes ) * osurf - > numindexes ) ;
osurf - > indexes = ( intptr_t ) poutindexes - ( intptr_t ) osurf ;
for ( ival = 0 ; ival < osurf - > numtris ; ival + + , pintriangle + + , poutindexes + = 3 )
{
for ( j = 0 ; j < 3 ; j + + )
poutindexes [ j ] = LittleLong ( pintriangle - > indexes [ j ] ) ;
}
for ( j = 0 ; j < 3 ; j + + )
{
osurf - > scale_origin [ j ] = 0 ;
osurf - > scale [ j ] = 1 / 64.0 ;
}
//guess at skin sizes
osurf - > skinwidth = 320 ;
osurf - > skinheight = 200 ;
//load the textures
2019-02-10 04:03:04 +00:00
if ( ! isDedicated )
2017-09-17 02:12:53 +00:00
{
2019-02-10 04:03:04 +00:00
pinshader = ( md3Shader_t * ) ( ( byte * ) pinsurface + LittleLong ( pinsurface - > ofsShaders ) ) ;
osurf - > numskins = LittleLong ( pinsurface - > numShaders ) ;
for ( j = 0 ; j < osurf - > numskins ; j + + , pinshader + + )
{
char texturename [ MAX_QPATH ] ;
char fullbrightname [ MAX_QPATH ] ;
char * ext ;
//texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names.
//our texture manager is too lame to scan all 1000 possibilities
if ( strchr ( pinshader - > name , ' / ' ) | | strchr ( pinshader - > name , ' \\ ' ) )
{ //so if there's a path then we want to use that.
q_strlcpy ( texturename , pinshader - > name , sizeof ( texturename ) ) ;
}
else
{ //and if there's no path then we want to prefix it with our own.
q_strlcpy ( texturename , mod - > name , sizeof ( texturename ) ) ;
* ( char * ) COM_SkipPath ( texturename ) = 0 ;
//and concat the specified name
q_strlcat ( texturename , pinshader - > name , sizeof ( texturename ) ) ;
}
//and make sure there's no extensions. these get ignored in q3, which is kinda annoying, but this is an md3 and standards are standards (and it makes luma easier).
ext = ( char * ) COM_FileGetExtension ( texturename ) ;
if ( * ext )
* - - ext = 0 ;
//luma has an extra postfix.
q_snprintf ( fullbrightname , sizeof ( fullbrightname ) , " %s_luma " , texturename ) ;
osurf - > gltextures [ j ] [ 0 ] = TexMgr_LoadImage ( mod , texturename , osurf - > skinwidth , osurf - > skinheight , SRC_EXTERNAL , NULL , texturename , 0 , TEXPREF_PAD | TEXPREF_ALPHA | TEXPREF_NOBRIGHT | TEXPREF_MIPMAP ) ;
osurf - > fbtextures [ j ] [ 0 ] = TexMgr_LoadImage ( mod , fullbrightname , osurf - > skinwidth , osurf - > skinheight , SRC_EXTERNAL , NULL , texturename , 0 , TEXPREF_PAD | TEXPREF_ALPHA | TEXPREF_FULLBRIGHT | TEXPREF_MIPMAP ) ;
osurf - > gltextures [ j ] [ 3 ] = osurf - > gltextures [ j ] [ 2 ] = osurf - > gltextures [ j ] [ 1 ] = osurf - > gltextures [ j ] [ 0 ] ;
osurf - > fbtextures [ j ] [ 3 ] = osurf - > fbtextures [ j ] [ 2 ] = osurf - > fbtextures [ j ] [ 1 ] = osurf - > fbtextures [ j ] [ 0 ] ;
2017-09-17 02:12:53 +00:00
}
2019-02-10 04:03:04 +00:00
if ( osurf - > numskins )
{
osurf - > skinwidth = osurf - > gltextures [ 0 ] [ 0 ] - > source_width ;
osurf - > skinheight = osurf - > gltextures [ 0 ] [ 0 ] - > source_height ;
2017-09-17 02:12:53 +00:00
}
}
//and figure out the texture coords properly, now we know the actual sizes.
pinst = ( md3St_t * ) ( ( byte * ) pinsurface + LittleLong ( pinsurface - > ofsSt ) ) ;
poutst = ( aliasmesh_t * ) Hunk_Alloc ( sizeof ( * poutst ) * osurf - > numverts ) ;
osurf - > meshdesc = ( intptr_t ) poutst - ( intptr_t ) osurf ;
for ( j = 0 ; j < osurf - > numverts ; j + + )
{
poutst [ j ] . vertindex = j ; //how is this useful?
poutst [ j ] . st [ 0 ] = pinst - > s ;
poutst [ j ] . st [ 1 ] = pinst - > t ;
}
}
GLMesh_LoadVertexBuffer ( mod , outhdr ) ;
//small violation of the spec, but it seems like noone else uses it.
mod - > flags = LittleLong ( pinheader - > flags ) ;
mod - > type = mod_alias ;
Mod_CalcAliasBounds ( outhdr ) ; //johnfitz
//
// move the complete, relocatable alias model to the cache
//
end = Hunk_LowMark ( ) ;
total = end - start ;
Cache_Alloc ( & mod - > cache , total , loadname ) ;
if ( ! mod - > cache . data )
return ;
memcpy ( mod - > cache . data , outhdr , total ) ;
Hunk_FreeToLowMark ( start ) ;
}
2019-11-02 15:50:53 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
InterQuake Models .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Header :
*/
//Copyright (c) 2010-2019 Lee Salzman
//MIT License etc at: https://github.com/lsalzman/iqm
# define IQM_MAGIC "INTERQUAKEMODEL"
# define IQM_VERSION 2
struct iqmheader
{
char magic [ 16 ] ;
unsigned int version ;
unsigned int filesize ;
unsigned int flags ;
unsigned int num_text , ofs_text ; //text strings
unsigned int num_meshes , ofs_meshes ; //surface info
unsigned int num_vertexarrays , num_vertexes , ofs_vertexarrays ; //for loading vertex data
unsigned int num_triangles , ofs_triangles , ofs_adjacency ; //the index data+neighbours(which we ignore)
unsigned int num_joints , ofs_joints ; //mesh joints (base pose info)
unsigned int num_poses , ofs_poses ; //animated joints (num_poses should match num_joints)
unsigned int num_anims , ofs_anims ; //animations info
unsigned int num_frames , num_framechannels , ofs_frames , ofs_bounds ; //the actual per-pose(aka:single-frame) data
unsigned int num_comment , ofs_comment ; //extra stuff
unsigned int num_extensions , ofs_extensions ; //extra stuff
} ;
struct iqmmesh
{
unsigned int name ;
unsigned int material ;
unsigned int first_vertex , num_vertexes ;
unsigned int first_triangle , num_triangles ;
} ;
enum
{
IQM_POSITION = 0 ,
IQM_TEXCOORD = 1 ,
IQM_NORMAL = 2 ,
IQM_TANGENT = 3 ,
IQM_BLENDINDEXES = 4 ,
IQM_BLENDWEIGHTS = 5 ,
IQM_COLOR = 6 ,
IQM_CUSTOM = 0x10
} ;
enum
{
IQM_BYTE = 0 ,
IQM_UBYTE = 1 ,
IQM_SHORT = 2 ,
IQM_USHORT = 3 ,
IQM_INT = 4 ,
IQM_UINT = 5 ,
IQM_HALF = 6 ,
IQM_FLOAT = 7 ,
IQM_DOUBLE = 8
} ;
/*struct iqmtriangle
{
unsigned int vertex [ 3 ] ;
} ;
struct iqmadjacency
{
unsigned int triangle [ 3 ] ;
} ;
struct iqmjointv1
{
unsigned int name ;
int parent ;
float translate [ 3 ] , rotate [ 3 ] , scale [ 3 ] ;
} ; */
struct iqmjoint
{
unsigned int name ;
int parent ;
float translate [ 3 ] , rotate [ 4 ] , scale [ 3 ] ;
} ;
/*struct iqmposev1
{
int parent ;
unsigned int mask ;
float channeloffset [ 9 ] ;
float channelscale [ 9 ] ;
} ; */
struct iqmpose
{
int parent ;
unsigned int mask ;
float channeloffset [ 10 ] ;
float channelscale [ 10 ] ;
} ;
struct iqmanim
{
unsigned int name ;
unsigned int first_frame , num_frames ;
float framerate ;
unsigned int flags ;
} ;
enum
{
IQM_LOOP = 1 < < 0
} ;
struct iqmvertexarray
{
unsigned int type ;
unsigned int flags ;
unsigned int format ;
unsigned int size ;
unsigned int offset ;
} ;
/*struct iqmbounds
{
float bbmin [ 3 ] , bbmax [ 3 ] ;
float xyradius , radius ;
} ;
struct iqmextension
{
unsigned int name ;
unsigned int num_data , ofs_data ;
unsigned int ofs_extensions ; // pointer to next extension
} ; */
//IQM Implementation: Copyright 2019 spike, licensed like the rest of quakespasm.
static void IQM_LoadVertexes_Float ( float * o , size_t c , size_t numverts , const byte * buffer , const struct iqmvertexarray * va )
{
size_t j , k ;
if ( c ! = va - > size )
return ; //erk, too lazy to handle weirdness.
switch ( va - > format )
{
// case IQM_BYTE:
case IQM_UBYTE :
{ //weights+colours are often normalised bytes.
const byte * in = ( const byte * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] / 255.0 ;
}
}
break ;
// case IQM_SHORT:
// case IQM_USHORT:
// case IQM_INT:
// case IQM_UINT:
// case IQM_HALF:
case IQM_FLOAT :
{
const float * in = ( const float * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] ;
}
}
break ;
case IQM_DOUBLE :
{ //truncate, sorry...
const double * in = ( const double * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] ;
}
}
break ;
default :
return ; //oh bum. my laziness strikes again.
}
}
static void IQM_LoadVertexes_Index ( byte * o , size_t c , size_t numverts , const byte * buffer , const struct iqmvertexarray * va )
{
size_t j , k ;
if ( c ! = va - > size )
return ; //erk, too lazy to handle weirdness.
switch ( va - > format )
{
// case IQM_BYTE:
case IQM_UBYTE :
{
const byte * in = ( const byte * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] ;
}
}
break ;
// case IQM_SHORT:
case IQM_USHORT :
{ //truncate...
const unsigned short * in = ( const unsigned short * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] ;
}
}
break ;
// case IQM_INT:
case IQM_UINT :
{ //truncate... noesis likes writing these.
const unsigned int * in = ( const unsigned int * ) ( buffer + va - > offset ) ;
for ( j = 0 ; j < numverts ; j + + , in + = va - > size , o + = sizeof ( iqmvert_t ) / sizeof ( * o ) )
{
for ( k = 0 ; k < c ; k + + )
o [ k ] = in [ k ] ;
}
}
break ;
// case IQM_HALF:
// case IQM_FLOAT:
// case IQM_DOUBLE:
default :
return ; //oh bum. my laziness strikes again.
}
}
static void GenMatrixPosQuat4Scale ( const vec3_t pos , const vec4_t quat , const vec3_t scale , float result [ 12 ] )
{
float xx , xy , xz , xw , yy , yz , yw , zz , zw ;
float x2 , y2 , z2 ;
float s ;
x2 = quat [ 0 ] + quat [ 0 ] ;
y2 = quat [ 1 ] + quat [ 1 ] ;
z2 = quat [ 2 ] + quat [ 2 ] ;
xx = quat [ 0 ] * x2 ; xy = quat [ 0 ] * y2 ; xz = quat [ 0 ] * z2 ;
yy = quat [ 1 ] * y2 ; yz = quat [ 1 ] * z2 ; zz = quat [ 2 ] * z2 ;
xw = quat [ 3 ] * x2 ; yw = quat [ 3 ] * y2 ; zw = quat [ 3 ] * z2 ;
s = scale [ 0 ] ;
result [ 0 * 4 + 0 ] = s * ( 1.0f - ( yy + zz ) ) ;
result [ 1 * 4 + 0 ] = s * ( xy + zw ) ;
result [ 2 * 4 + 0 ] = s * ( xz - yw ) ;
s = scale [ 1 ] ;
result [ 0 * 4 + 1 ] = s * ( xy - zw ) ;
result [ 1 * 4 + 1 ] = s * ( 1.0f - ( xx + zz ) ) ;
result [ 2 * 4 + 1 ] = s * ( yz + xw ) ;
s = scale [ 2 ] ;
result [ 0 * 4 + 2 ] = s * ( xz + yw ) ;
result [ 1 * 4 + 2 ] = s * ( yz - xw ) ;
result [ 2 * 4 + 2 ] = s * ( 1.0f - ( xx + yy ) ) ;
result [ 0 * 4 + 3 ] = pos [ 0 ] ;
result [ 1 * 4 + 3 ] = pos [ 1 ] ;
result [ 2 * 4 + 3 ] = pos [ 2 ] ;
}
static void Matrix3x4_Invert_Simple ( const float * in1 , float * out )
{
// we only support uniform scaling, so assume the first row is enough
// (note the lack of sqrt here, because we're trying to undo the scaling,
// this means multiplying by the inverse scale twice - squaring it, which
// makes the sqrt a waste of time)
# if 1
double scale = 1.0 / ( in1 [ 0 ] * in1 [ 0 ] + in1 [ 1 ] * in1 [ 1 ] + in1 [ 2 ] * in1 [ 2 ] ) ;
# else
double scale = 3.0 / sqrt
( in1 - > m [ 0 ] [ 0 ] * in1 - > m [ 0 ] [ 0 ] + in1 - > m [ 0 ] [ 1 ] * in1 - > m [ 0 ] [ 1 ] + in1 - > m [ 0 ] [ 2 ] * in1 - > m [ 0 ] [ 2 ]
+ in1 - > m [ 1 ] [ 0 ] * in1 - > m [ 1 ] [ 0 ] + in1 - > m [ 1 ] [ 1 ] * in1 - > m [ 1 ] [ 1 ] + in1 - > m [ 1 ] [ 2 ] * in1 - > m [ 1 ] [ 2 ]
+ in1 - > m [ 2 ] [ 0 ] * in1 - > m [ 2 ] [ 0 ] + in1 - > m [ 2 ] [ 1 ] * in1 - > m [ 2 ] [ 1 ] + in1 - > m [ 2 ] [ 2 ] * in1 - > m [ 2 ] [ 2 ] ) ;
scale * = scale ;
# endif
// invert the rotation by transposing and multiplying by the squared
// recipricol of the input matrix scale as described above
out [ 0 ] = in1 [ 0 ] * scale ;
out [ 1 ] = in1 [ 4 ] * scale ;
out [ 2 ] = in1 [ 8 ] * scale ;
out [ 4 ] = in1 [ 1 ] * scale ;
out [ 5 ] = in1 [ 5 ] * scale ;
out [ 6 ] = in1 [ 9 ] * scale ;
out [ 8 ] = in1 [ 2 ] * scale ;
out [ 9 ] = in1 [ 6 ] * scale ;
out [ 10 ] = in1 [ 10 ] * scale ;
// invert the translate
out [ 3 ] = - ( in1 [ 3 ] * out [ 0 ] + in1 [ 7 ] * out [ 1 ] + in1 [ 11 ] * out [ 2 ] ) ;
out [ 7 ] = - ( in1 [ 3 ] * out [ 4 ] + in1 [ 7 ] * out [ 5 ] + in1 [ 11 ] * out [ 6 ] ) ;
out [ 11 ] = - ( in1 [ 3 ] * out [ 8 ] + in1 [ 7 ] * out [ 9 ] + in1 [ 11 ] * out [ 10 ] ) ;
}
void Mod_LoadIQMModel ( qmodel_t * mod , const void * buffer )
{
const struct iqmheader * pinheader ;
const char * pintext ;
const struct iqmmesh * pinsurface ;
const struct iqmanim * pinframes ;
const unsigned int * pintriangle ;
unsigned short * poutindexes ;
iqmvert_t * poutvert ;
int size ;
int start , end , total ;
int ival , j , a ;
int numsurfs , surf ;
aliashdr_t * outhdr ;
int numverts , firstidx , firstvert ;
int numanims ;
bonepose_t * outposes ;
boneinfo_t * outbones ;
int numposes , numjoints ;
start = Hunk_LowMark ( ) ;
pinheader = ( const struct iqmheader * ) buffer ;
if ( strcmp ( pinheader - > magic , IQM_MAGIC ) )
Sys_Error ( " %s has invalid magic for iqm file " , mod - > name ) ;
if ( LittleLong ( pinheader - > version ) ! = IQM_VERSION ) //v1 is outdated.
Sys_Error ( " %s is an unsupported version, %i must be %i " , mod - > name , LittleLong ( pinheader - > version ) , IQM_VERSION ) ;
pintext = buffer + LittleLong ( pinheader - > ofs_text ) ;
numsurfs = LittleLong ( pinheader - > num_meshes ) ;
if ( ! numsurfs )
Sys_Error ( " %s has no surfaces (animation-only iqms are not supported) " , mod - > name ) ;
if ( pinheader - > num_vertexes > 0xffff ) //indexes is an unsigned short.
Sys_Error ( " %s has too many verts (%u>%u) " , mod - > name , pinheader - > num_vertexes , 0xffffu ) ;
numanims = LittleLong ( pinheader - > num_anims ) ;
size = sizeof ( aliashdr_t ) + q_max ( 1 , numanims - 1 ) * sizeof ( outhdr - > frames [ 0 ] ) ;
outhdr = ( aliashdr_t * ) Hunk_AllocName ( size * numsurfs , loadname ) ;
numverts = LittleLong ( pinheader - > num_vertexes ) ;
poutvert = ( iqmvert_t * ) Hunk_Alloc ( sizeof ( * poutvert ) * numverts ) ;
for ( j = 0 ; j < numverts ; j + + ) //initialise verts, just in case.
poutvert [ j ] . rgba [ 0 ] = poutvert [ j ] . rgba [ 1 ] = poutvert [ j ] . rgba [ 2 ] = poutvert [ j ] . rgba [ 3 ] = poutvert [ j ] . weight [ 0 ] = 1 ;
for ( a = 0 ; a < LittleLong ( pinheader - > num_vertexarrays ) ; a + + )
{
const struct iqmvertexarray * va = ( const struct iqmvertexarray * ) ( buffer + LittleLong ( pinheader - > ofs_vertexarrays ) ) + a ;
switch ( va - > type )
{
case IQM_POSITION : IQM_LoadVertexes_Float ( poutvert - > xyz , 3 , numverts , buffer , va ) ; break ;
case IQM_TEXCOORD : IQM_LoadVertexes_Float ( poutvert - > st , 2 , numverts , buffer , va ) ; break ;
case IQM_NORMAL : IQM_LoadVertexes_Float ( poutvert - > norm , 3 , numverts , buffer , va ) ; break ;
//case IQM_TANGENT: IQM_LoadVertexes_Float(poutvert->tang, 4, numverts, buffer, va); break; //bitangent must be calced using a crossproduct and the fourth component (for direction). we don't need this (unless you want rtlights or bumpmaps)
case IQM_COLOR : IQM_LoadVertexes_Float ( poutvert - > rgba , 4 , numverts , buffer , va ) ; break ;
case IQM_BLENDINDEXES : IQM_LoadVertexes_Index ( poutvert - > idx , 4 , numverts , buffer , va ) ; break ;
case IQM_BLENDWEIGHTS : IQM_LoadVertexes_Float ( poutvert - > weight , 4 , numverts , buffer , va ) ; break ;
default :
continue ; //no idea what it is. probably custom
}
}
numposes = LittleLong ( pinheader - > num_frames ) ;
numjoints = LittleLong ( pinheader - > num_poses ) ;
if ( pinheader - > num_poses = = pinheader - > num_joints )
{
const unsigned short * pinframedata = ( const unsigned short * ) ( buffer + pinheader - > ofs_frames ) ;
const struct iqmpose * pinajoint = ( const struct iqmpose * ) ( buffer + pinheader - > ofs_poses ) , * p ;
vec3_t pos , scale ;
vec4_t quat ;
outposes = Hunk_Alloc ( sizeof ( * outposes ) * numposes * numjoints ) ;
for ( a = 0 ; a < numposes ; a + + )
{
for ( j = 0 , p = pinajoint ; j < numjoints ; j + + , p + + )
{
unsigned int mask = LittleLong ( p - > mask ) ;
pos [ 0 ] = LittleFloat ( p - > channeloffset [ 0 ] ) ; if ( mask & 1 ) pos [ 0 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 0 ] ) ;
pos [ 1 ] = LittleFloat ( p - > channeloffset [ 1 ] ) ; if ( mask & 2 ) pos [ 1 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 1 ] ) ;
pos [ 2 ] = LittleFloat ( p - > channeloffset [ 2 ] ) ; if ( mask & 4 ) pos [ 2 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 2 ] ) ;
quat [ 0 ] = LittleFloat ( p - > channeloffset [ 3 ] ) ; if ( mask & 8 ) quat [ 0 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 3 ] ) ;
quat [ 1 ] = LittleFloat ( p - > channeloffset [ 4 ] ) ; if ( mask & 16 ) quat [ 1 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 4 ] ) ;
quat [ 2 ] = LittleFloat ( p - > channeloffset [ 5 ] ) ; if ( mask & 32 ) quat [ 2 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 5 ] ) ;
quat [ 3 ] = LittleFloat ( p - > channeloffset [ 6 ] ) ; if ( mask & 64 ) quat [ 3 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 6 ] ) ;
scale [ 0 ] = LittleFloat ( p - > channeloffset [ 7 ] ) ; if ( mask & 128 ) scale [ 0 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 7 ] ) ;
scale [ 1 ] = LittleFloat ( p - > channeloffset [ 8 ] ) ; if ( mask & 256 ) scale [ 1 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 8 ] ) ;
scale [ 2 ] = LittleFloat ( p - > channeloffset [ 9 ] ) ; if ( mask & 512 ) scale [ 2 ] + = ( unsigned short ) LittleShort ( * pinframedata + + ) * LittleFloat ( p - > channelscale [ 9 ] ) ;
//fixme: should probably save the 10 values above and slerp, but its simpler to just save+lerp a matrix (although this does result in denormalisation when interpolating).
GenMatrixPosQuat4Scale ( pos , quat , scale , outposes [ ( a * numjoints + j ) ] . mat ) ;
}
}
}
else
{ //panic! panic! something weird is going on!
numposes = 0 ;
numjoints = 0 ;
outposes = NULL ;
}
{
const struct iqmjoint * pinbjoint = ( const struct iqmjoint * ) ( buffer + pinheader - > ofs_joints ) ;
bonepose_t basepose [ 256 ] , rel ;
vec3_t pos , scale ;
vec4_t quat ;
outbones = Hunk_Alloc ( sizeof ( * outbones ) * numjoints ) ;
for ( j = 0 ; j < numjoints ; j + + )
{
outbones [ j ] . parent = LittleLong ( pinbjoint [ j ] . parent ) ;
q_strlcpy ( outbones [ j ] . name , pintext + LittleLong ( pinbjoint [ j ] . name ) , sizeof ( outbones [ j ] . name ) ) ;
pos [ 0 ] = LittleFloat ( pinbjoint [ j ] . translate [ 0 ] ) ;
pos [ 1 ] = LittleFloat ( pinbjoint [ j ] . translate [ 1 ] ) ;
pos [ 2 ] = LittleFloat ( pinbjoint [ j ] . translate [ 2 ] ) ;
quat [ 0 ] = LittleFloat ( pinbjoint [ j ] . rotate [ 0 ] ) ;
quat [ 1 ] = LittleFloat ( pinbjoint [ j ] . rotate [ 1 ] ) ;
quat [ 2 ] = LittleFloat ( pinbjoint [ j ] . rotate [ 2 ] ) ;
quat [ 3 ] = LittleFloat ( pinbjoint [ j ] . rotate [ 3 ] ) ;
scale [ 0 ] = LittleFloat ( pinbjoint [ j ] . scale [ 0 ] ) ;
scale [ 1 ] = LittleFloat ( pinbjoint [ j ] . scale [ 1 ] ) ;
scale [ 2 ] = LittleFloat ( pinbjoint [ j ] . scale [ 2 ] ) ;
GenMatrixPosQuat4Scale ( pos , quat , scale , rel . mat ) ;
//urgh, these are relative.
if ( outbones [ j ] . parent < 0 )
memcpy ( basepose [ j ] . mat , rel . mat , sizeof ( rel . mat ) ) ;
else
R_ConcatTransforms ( ( void * ) basepose [ outbones [ j ] . parent ] . mat , ( void * ) rel . mat , ( void * ) basepose [ j ] . mat ) ;
Matrix3x4_Invert_Simple ( basepose [ j ] . mat , outbones [ j ] . inverse . mat ) ;
//and now we have the inversion matrix to use to undo the bone positions baked into the vertex data.
}
}
mod - > numframes = q_max ( 1 , numanims ) ;
for ( surf = 0 , pinsurface = ( const struct iqmmesh * ) ( buffer + LittleLong ( pinheader - > ofs_meshes ) ) ; surf < numsurfs ; surf + + , pinsurface + + )
{
aliashdr_t * osurf = ( aliashdr_t * ) ( ( byte * ) outhdr + size * surf ) ;
if ( surf + 1 < numsurfs )
osurf - > nextsurface = size ;
else
osurf - > nextsurface = 0 ;
osurf - > poseverttype = PV_IQM ;
osurf - > numverts_vbo = osurf - > numverts = LittleLong ( pinsurface - > num_vertexes ) ;
firstvert = LittleLong ( pinsurface - > first_vertex ) ;
osurf - > vertexes = ( intptr_t ) ( poutvert + firstvert ) - ( intptr_t ) osurf ;
osurf - > numverts = LittleLong ( pinsurface - > num_vertexes ) ;
osurf - > nummorphposes = 1 ; //as a skeletal model, we do all our animations via bones rather than vertex morphs.
osurf - > numtris = LittleLong ( pinsurface - > num_triangles ) ;
osurf - > numindexes = osurf - > numtris * 3 ;
poutindexes = ( unsigned short * ) Hunk_Alloc ( sizeof ( * poutindexes ) * osurf - > numindexes ) ;
osurf - > indexes = ( intptr_t ) poutindexes - ( intptr_t ) osurf ;
pintriangle = ( const unsigned int * ) ( buffer + LittleLong ( pinheader - > ofs_triangles ) ) ;
firstidx = LittleLong ( pinsurface - > first_triangle ) * 3 ;
pintriangle + = firstidx ;
for ( j = 0 ; j < osurf - > numindexes ; j + + )
poutindexes [ j ] = pintriangle [ j ] - firstvert ;
pinframes = ( const struct iqmanim * ) ( buffer + pinheader - > ofs_anims ) ;
for ( a = 0 ; a < numanims ; a + + , pinframes + + )
{
osurf - > frames [ a ] . firstpose = LittleLong ( pinframes - > first_frame ) ;
osurf - > frames [ a ] . numposes = LittleLong ( pinframes - > num_frames ) ;
osurf - > frames [ a ] . interval = LittleFloat ( pinframes - > framerate ) ;
if ( ! osurf - > frames [ a ] . interval )
osurf - > frames [ a ] . interval = 20 ;
osurf - > frames [ a ] . interval = 1.0 / osurf - > frames [ a ] . interval ;
if ( LittleLong ( pinframes - > flags ) & IQM_LOOP )
/*FIXME*/ ;
q_strlcpy ( osurf - > frames [ a ] . name , pintext + LittleLong ( pinframes - > name ) , sizeof ( osurf - > frames [ ival ] . name ) ) ;
for ( j = 0 ; j < 3 ; j + + )
{ //fixme...
osurf - > frames [ a ] . bboxmin . v [ j ] = 0 ;
osurf - > frames [ a ] . bboxmax . v [ j ] = 255 ;
}
}
for ( ; a < 1 ; a + + , pinframes + + )
{ //unanimated models need to pick their morphpose without warnings.
osurf - > frames [ a ] . firstpose = 0 ;
osurf - > frames [ a ] . numposes = 1 ;
osurf - > frames [ a ] . interval = 0.1 ;
q_strlcpy ( osurf - > frames [ a ] . name , " " , sizeof ( osurf - > frames [ ival ] . name ) ) ;
for ( j = 0 ; j < 3 ; j + + )
{ //fixme...
osurf - > frames [ a ] . bboxmin . v [ j ] = 0 ;
osurf - > frames [ a ] . bboxmax . v [ j ] = 255 ;
}
}
osurf - > numframes = a ;
if ( numposes )
{
osurf - > numboneposes = numposes ;
osurf - > boneposedata = ( intptr_t ) outposes - ( intptr_t ) osurf ;
}
osurf - > numbones = numjoints ;
osurf - > boneinfo = ( intptr_t ) outbones - ( intptr_t ) osurf ;
for ( j = 0 ; j < 3 ; j + + )
{
osurf - > scale_origin [ j ] = 0 ;
osurf - > scale [ j ] = 1.0 ;
}
//skin size is irrelevant
osurf - > skinwidth = 1 ;
osurf - > skinheight = 1 ;
//load the textures
if ( ! isDedicated )
{
const char * pinshader = pintext + LittleLong ( pinsurface - > material ) ;
osurf - > numskins = 1 ;
for ( j = 0 ; j < 1 ; j + + , pinshader + + )
{
char texturename [ MAX_QPATH ] ;
char fullbrightname [ MAX_QPATH ] ;
char * ext ;
//texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names.
//our texture manager is too lame to scan all 1000 possibilities
if ( strchr ( pinshader , ' / ' ) | | strchr ( pinshader , ' \\ ' ) )
{ //so if there's a path then we want to use that.
q_strlcpy ( texturename , pinshader , sizeof ( texturename ) ) ;
}
else
{ //and if there's no path then we want to prefix it with our own.
q_strlcpy ( texturename , mod - > name , sizeof ( texturename ) ) ;
* ( char * ) COM_SkipPath ( texturename ) = 0 ;
//and concat the specified name
q_strlcat ( texturename , pinshader , sizeof ( texturename ) ) ;
}
//and make sure there's no extensions. these get ignored in q3, which is kinda annoying, but this is an md3 and standards are standards (and it makes luma easier).
ext = ( char * ) COM_FileGetExtension ( texturename ) ;
if ( * ext )
* - - ext = 0 ;
//luma has an extra postfix.
q_snprintf ( fullbrightname , sizeof ( fullbrightname ) , " %s_luma " , texturename ) ;
osurf - > gltextures [ j ] [ 0 ] = TexMgr_LoadImage ( mod , texturename , osurf - > skinwidth , osurf - > skinheight , SRC_EXTERNAL , NULL , texturename , 0 , TEXPREF_PAD | TEXPREF_ALPHA | TEXPREF_NOBRIGHT | TEXPREF_MIPMAP ) ;
osurf - > fbtextures [ j ] [ 0 ] = NULL ; //TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP);
osurf - > gltextures [ j ] [ 3 ] = osurf - > gltextures [ j ] [ 2 ] = osurf - > gltextures [ j ] [ 1 ] = osurf - > gltextures [ j ] [ 0 ] ;
osurf - > fbtextures [ j ] [ 3 ] = osurf - > fbtextures [ j ] [ 2 ] = osurf - > fbtextures [ j ] [ 1 ] = osurf - > fbtextures [ j ] [ 0 ] ;
}
if ( osurf - > numskins )
{
osurf - > skinwidth = osurf - > gltextures [ 0 ] [ 0 ] - > source_width ;
osurf - > skinheight = osurf - > gltextures [ 0 ] [ 0 ] - > source_height ;
}
}
}
GLMesh_LoadVertexBuffer ( mod , outhdr ) ;
//small violation of the spec, but it seems like noone else uses it.
mod - > flags = LittleLong ( pinheader - > flags ) ;
mod - > type = mod_alias ;
Mod_CalcAliasBounds ( outhdr ) ; //johnfitz
//
// move the complete, relocatable alias model to the cache
//
end = Hunk_LowMark ( ) ;
total = end - start ;
Cache_Alloc ( & mod - > cache , total , loadname ) ;
if ( ! mod - > cache . data )
return ;
memcpy ( mod - > cache . data , outhdr , total ) ;
Hunk_FreeToLowMark ( start ) ;
}