//----------------------------------------------------------------------------- // Updates the relative orientation of the camera, spring mode //----------------------------------------------------------------------------- void CWeaponIFMSteadyCam::UpdateDirectRelativeOrientation() { // Compute a player to steadycam matrix VMatrix steadyCamToPlayer; MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer ); MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition ); // Compute a forward direction Vector vecCurrentForward; MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward ); // Before any updating occurs, sample the current // world-space direction of the mouse Vector vecDesiredDirection; ComputeMouseRay( steadyCamToPlayer, vecDesiredDirection ); // rebuild a roll-less orientation based on that direction vector matrix3x4_t mat; MatrixFromForwardDirection( vecDesiredDirection, mat ); MatrixAngles( mat, m_angRelativeAngles ); Assert( m_angRelativeAngles.IsValid() ); m_vecActualViewOffset -= m_vecViewOffset; m_vecViewOffset.Init(); }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // adnan // want to add an angles modifier key bool CGravControllerPoint::UpdateObject( CBasePlayer *pPlayer, CBaseEntity *pEntity ) { IPhysicsObject *pPhysics = GetPhysObjFromPhysicsBone( pEntity, m_attachedPhysicsBone ); if ( !pEntity || !pPhysics ) { return false; } #ifdef ARGG // adnan // if we've been rotating it, set it to its proper new angles (change m_attachedAnglesPlayerSpace while modifier) //Pickup_GetRotatedCarryAngles( pEntity, pPlayer, pPlayer->EntityToWorldTransform(), angles ); // added the ... && (mousedx | mousedy) so we dont have to calculate if no mouse movement // UPDATE: m_vecRotatedCarryAngles has become a temp variable... can be cleaned up by using actual temp vars #ifdef CLIENT_DLL if( m_bHasRotatedCarryAngles && (pPlayer->m_pCurrentCommand->mousedx || pPlayer->m_pCurrentCommand->mousedy) ) #else if( m_bHasRotatedCarryAngles && (pPlayer->GetCurrentCommand()->mousedx || pPlayer->GetCurrentCommand()->mousedy) ) #endif { // method II: relative orientation VMatrix vDeltaRotation, vCurrentRotation, vNewRotation; MatrixFromAngles( m_targetRotation, vCurrentRotation ); #ifdef CLIENT_DLL m_vecRotatedCarryAngles[YAW] = pPlayer->m_pCurrentCommand->mousedx*0.05; m_vecRotatedCarryAngles[PITCH] = pPlayer->m_pCurrentCommand->mousedy*-0.05; #else m_vecRotatedCarryAngles[YAW] = pPlayer->GetCurrentCommand()->mousedx*0.05; m_vecRotatedCarryAngles[PITCH] = pPlayer->GetCurrentCommand()->mousedy*-0.05; #endif m_vecRotatedCarryAngles[ROLL] = 0; MatrixFromAngles( m_vecRotatedCarryAngles, vDeltaRotation ); MatrixMultiply(vDeltaRotation, vCurrentRotation, vNewRotation); MatrixToAngles( vNewRotation, m_targetRotation ); } // end adnan #endif SetTargetPosition( m_targetPosition, m_targetRotation ); return true; }
void MatrixMultiplyRotation(matrix_t m, vec_t pitch, vec_t yaw, vec_t roll) { matrix_t tmp, rot; MatrixCopy(m, tmp); MatrixFromAngles(rot, pitch, yaw, roll); MatrixMultiply(rot, tmp, m); }
//----------------------------------------------------------------------------- // Computes the position of the canister //----------------------------------------------------------------------------- void CEnvHeadcrabCanisterShared::GetPositionAtTime( float flTime, Vector &vecPosition, QAngle &vecAngles ) { float flDeltaTime = flTime - m_flLaunchTime; if ( flDeltaTime > m_flFlightTime ) { flDeltaTime = m_flFlightTime; } VMatrix initToWorld; if ( m_bLaunchedFromWithinWorld || m_bInSkybox ) { VectorMA( m_vecStartPosition, flDeltaTime * m_flHorizSpeed, m_vecParabolaDirection, vecPosition ); vecPosition.z += m_flInitialZSpeed * flDeltaTime + 0.5f * m_flZAcceleration * flDeltaTime * flDeltaTime; Vector vecLeft; CrossProduct( m_vecParabolaDirection, Vector( 0, 0, 1 ), vecLeft ); Vector vecForward; VectorMultiply( m_vecParabolaDirection, -1.0f, vecForward ); vecForward.z = -(m_flInitialZSpeed + m_flZAcceleration * flDeltaTime) / m_flHorizSpeed; // This is -dz/dx. VectorNormalize( vecForward ); Vector vecUp; CrossProduct( vecForward, vecLeft, vecUp ); initToWorld.SetBasisVectors( vecForward, vecLeft, vecUp ); } else { flDeltaTime -= m_flWorldEnterTime; Vector vecVelocity; VectorMultiply( m_vecDirection, m_flFlightSpeed, vecVelocity ); VectorMA( m_vecEnterWorldPosition, flDeltaTime, vecVelocity, vecPosition ); MatrixFromAngles( m_vecStartAngles.Get(), initToWorld ); } VMatrix rotation; MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), flDeltaTime * ROTATION_SPEED ); VMatrix newAngles; MatrixMultiply( initToWorld, rotation, newAngles ); MatrixToAngles( newAngles, vecAngles ); }
//----------------------------------------------------------------------------- // Read in worldcraft data... //----------------------------------------------------------------------------- bool CVGuiScreen::KeyValue( const char *szKeyName, const char *szValue ) { //!! temp hack, until worldcraft is fixed // strip the # tokens from (duplicate) key names char *s = (char *)strchr( szKeyName, '#' ); if ( s ) { *s = '\0'; } if ( FStrEq( szKeyName, "panelname" )) { SetPanelName( szValue ); return true; } // NOTE: Have to do these separate because they set two values instead of one if( FStrEq( szKeyName, "angles" ) ) { Assert( GetMoveParent() == NULL ); QAngle angles; UTIL_StringToVector( angles.Base(), szValue ); // Because the vgui screen basis is strange (z is front, y is up, x is right) // we need to rotate the typical basis before applying it VMatrix mat, rotation, tmp; MatrixFromAngles( angles, mat ); MatrixBuildRotationAboutAxis( rotation, Vector( 0, 1, 0 ), 90 ); MatrixMultiply( mat, rotation, tmp ); MatrixBuildRotateZ( rotation, 90 ); MatrixMultiply( tmp, rotation, mat ); MatrixToAngles( mat, angles ); SetAbsAngles( angles ); return true; } return BaseClass::KeyValue( szKeyName, szValue ); }
void Draw_Scene(void (*drawFunc) (void)) { #if defined(USE_OPENGL) Uint8 *keys; matrix_t rotation; vec3_t forward, right, up; qboolean mouseGrabbed; qboolean mouseGrabbedLastFrame; int oldTime, newTime, deltaTime; // for frame independent movement mouseGrabbed = qfalse; mouseGrabbedLastFrame = qfalse; oldTime = SDL_GetTicks(); while(1) { SDL_Event event; newTime = SDL_GetTicks(); deltaTime = newTime - oldTime; //Sys_Printf(" deltaTime (%5.2f seconds)\n", (deltaTime / 1000.0)); MatrixFromAngles(rotation, drawAngles[PITCH], drawAngles[YAW], drawAngles[ROLL]); MatrixToVectorsFRU(rotation, forward, right, up); while(SDL_PollEvent(&event)) { switch (event.type) { case SDL_VIDEORESIZE: { drawScreen = SDL_SetVideoMode(event.resize.w, event.resize.h, drawVideo->vfmt->BitsPerPixel, SDL_OPENGL | SDL_RESIZABLE); if(drawScreen) { Reshape(drawScreen->w, drawScreen->h); } else { /* Uh oh, we couldn't set the new video mode?? */ ; } break; } case SDL_MOUSEMOTION: { if(mouseGrabbed && !mouseGrabbedLastFrame) { drawAngles[PITCH] += event.motion.yrel; drawAngles[YAW] -= event.motion.xrel; } mouseGrabbedLastFrame = qfalse; break; } case SDL_MOUSEBUTTONDOWN: { switch (event.button.button) { case 3: { // K_MOUSE2; if(!mouseGrabbed) { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(0); mouseGrabbed = qtrue; mouseGrabbedLastFrame = qtrue; } else { SDL_ShowCursor(1); SDL_WM_GrabInput(SDL_GRAB_OFF); mouseGrabbed = qfalse; } break; } default: break; } break; } case SDL_QUIT: { Draw_Shutdown(); return; } default: break; } } keys = SDL_GetKeyState(NULL); if(keys[SDLK_ESCAPE]) { Draw_Shutdown(); return; } if(keys[SDLK_w]) { if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, 0.5 * deltaTime, forward, drawOrigin); } else { VectorMA(drawOrigin, 1.0 * deltaTime, forward, drawOrigin); } } if(keys[SDLK_s]) { if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, -0.5 * deltaTime, forward, drawOrigin); } else { VectorMA(drawOrigin, -1.0 * deltaTime, forward, drawOrigin); } } if(keys[SDLK_a]) { if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, -0.5 * deltaTime, right, drawOrigin); } else { VectorMA(drawOrigin, -1.0 * deltaTime, right, drawOrigin); } } if(keys[SDLK_d]) { if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, 0.5 * deltaTime, right, drawOrigin); } else { VectorMA(drawOrigin, 1.0 * deltaTime, right, drawOrigin); } } if(keys[SDLK_SPACE]) { //drawOrigin[2] += 1.0 * deltaTime; if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, 0.5 * deltaTime, up, drawOrigin); } else { VectorMA(drawOrigin, 1.0 * deltaTime, up, drawOrigin); } } if(keys[SDLK_c]) { //drawOrigin[2] -= 1.0 * deltaTime; if(SDL_GetModState() & KMOD_SHIFT) { VectorMA(drawOrigin, -0.5 * deltaTime, up, drawOrigin); } else { VectorMA(drawOrigin, -1.0 * deltaTime, up, drawOrigin); } } if(keys[SDLK_UP]) { drawAngles[PITCH] -= 1.0 * deltaTime; } if(keys[SDLK_DOWN]) { drawAngles[PITCH] += 1.0 * deltaTime; } if(keys[SDLK_LEFT]) { drawAngles[YAW] += 1.0 * deltaTime; } if(keys[SDLK_RIGHT]) { drawAngles[YAW] -= 1.0 * deltaTime; } // check to make sure the angles haven't wrapped if(drawAngles[PITCH] < -90) { drawAngles[PITCH] = -90; } else if(drawAngles[PITCH] > 90) { drawAngles[PITCH] = 90; } Draw_BeginScene(); drawFunc(); Draw_EndScene(); oldTime = newTime; } #endif // #if defined(USE_OPENGL) }
VMatrix SetupMatrixAngles(const QAngle &vAngles) { VMatrix mRet; MatrixFromAngles( vAngles, mRet ); return mRet; }
void CWeaponIFMSteadyCam::UpdateRelativeOrientation() { if ( m_bIsLocked ) return; if ( m_bInDirectMode ) { UpdateDirectRelativeOrientation(); return; } if ( ( m_vecViewOffset.x == 0.0f ) && ( m_vecViewOffset.y == 0.0f ) ) return; // Compute a player to steadycam matrix VMatrix steadyCamToPlayer; MatrixFromAngles( m_angRelativeAngles, steadyCamToPlayer ); MatrixSetColumn( steadyCamToPlayer, 3, m_vecRelativePosition ); Vector vecCurrentForward; MatrixGetColumn( steadyCamToPlayer, 0, &vecCurrentForward ); // Create a ray in steadycam space float flMaxD = 1.0f / tan( M_PI * m_flFOV / 360.0f ); // Remap offsets into normalized space float flViewX = m_vecViewOffset.x / ( 384 / 2 ); float flViewY = m_vecViewOffset.y / ( 288 / 2 ); flViewX *= flMaxD * ifm_steadycam_mousefactor.GetFloat(); flViewY *= flMaxD * ifm_steadycam_mousefactor.GetFloat(); Vector vecSelectionDir( 1.0f, -flViewX, -flViewY ); VectorNormalize( vecSelectionDir ); // Rotate the ray into player coordinates Vector vecDesiredDirection; Vector3DMultiply( steadyCamToPlayer, vecSelectionDir, vecDesiredDirection ); float flDot = DotProduct( vecDesiredDirection, vecCurrentForward ); flDot = clamp( flDot, -1.0f, 1.0f ); float flAngle = 180.0f * acos( flDot ) / M_PI; if ( flAngle < 1e-3 ) { matrix3x4_t mat; MatrixFromForwardDirection( vecDesiredDirection, mat ); MatrixAngles( mat, m_angRelativeAngles ); return; } Vector vecAxis; CrossProduct( vecCurrentForward, vecDesiredDirection, vecAxis ); VectorNormalize( vecAxis ); float flRotateRate = ifm_steadycam_rotaterate.GetFloat(); if ( flRotateRate < 1.0f ) { flRotateRate = 1.0f; } float flRateFactor = flAngle / flRotateRate; flRateFactor *= flRateFactor * flRateFactor; float flRate = flRateFactor * 30.0f; float flMaxAngle = gpGlobals->frametime * flRate; flAngle = clamp( flAngle, 0.0f, flMaxAngle ); Vector vecNewForard; VMatrix rotation; MatrixBuildRotationAboutAxis( rotation, vecAxis, flAngle ); Vector3DMultiply( rotation, vecCurrentForward, vecNewForard ); matrix3x4_t mat; MatrixFromForwardDirection( vecNewForard, mat ); MatrixAngles( mat, m_angRelativeAngles ); Assert( m_angRelativeAngles.IsValid() ); }
static void PopulateTraceNodes(void) { int i, m, frame, castShadows; float temp; entity_t *e; const char *value; picoModel_t *model; vec3_t origin, scale, angles; matrix_t rotation; matrix_t transform; /* add worldspawn triangles */ MatrixIdentity(transform); PopulateWithBSPModel(&bspModels[0], transform); /* walk each entity list */ for(i = 1; i < numEntities; i++) { /* get entity */ e = &entities[i]; /* get shadow flags */ castShadows = ENTITY_CAST_SHADOWS; GetEntityShadowFlags(e, NULL, &castShadows, NULL); /* early out? */ if(!castShadows) continue; /* get entity origin */ GetVectorForKey(e, "origin", origin); /* get "angle" (yaw) or "angles" (pitch yaw roll) */ MatrixIdentity(rotation); angles[0] = angles[1] = angles[2] = 0.0f; value = ValueForKey(e, "angle"); if(value[0] != '\0') { angles[1] = atof(value); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e, "angles"); if(value[0] != '\0') { sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e, "rotation"); if(value[0] != '\0') { sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]); } /* get scale */ scale[0] = scale[1] = scale[2] = 1.0f; temp = FloatForKey(e, "modelscale"); if(temp != 0.0f) scale[0] = scale[1] = scale[2] = temp; value = ValueForKey(e, "modelscale_vec"); if(value[0] != '\0') sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]); MatrixMultiplyScale(rotation, scale[0], scale[1], scale[2]); /* set transform matrix */ MatrixIdentity(transform); MatrixSetupTransformFromRotation(transform, rotation, origin); //% m4x4_pivoted_transform_by_vec3(transform, origin, angles, eXYZ, scale, vec3_origin); /* get model */ value = ValueForKey(e, "model"); /* switch on model type */ switch (value[0]) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi(&value[1]); if(m <= 0 || m >= numBSPModels) continue; PopulateWithBSPModel(&bspModels[m], transform); break; /* external model */ default: frame = IntForKey(e, "_frame"); model = LoadModel((char *)value, frame); if(model == NULL) continue; PopulateWithPicoModel(castShadows, model, transform); continue; } /* get model2 */ value = ValueForKey(e, "model2"); /* switch on model type */ switch (value[0]) { /* no model */ case '\0': break; /* bsp model */ case '*': m = atoi(&value[1]); if(m <= 0 || m >= numBSPModels) continue; PopulateWithBSPModel(&bspModels[m], transform); break; /* external model */ default: frame = IntForKey(e, "_frame2"); model = LoadModel((char *)value, frame); if(model == NULL) continue; PopulateWithPicoModel(castShadows, model, transform); continue; } } }
/* ================= R_LoadPSK ================= */ qboolean R_LoadPSK( model_t *mod, void *buffer, int bufferSize, const char *modName ) { int i, j, k; memStream_t *stream = NULL; axChunkHeader_t chunkHeader; int numPoints; axPoint_t *point; axPoint_t *points = NULL; int numVertexes; axVertex_t *vertex; axVertex_t *vertexes = NULL; //int numSmoothGroups; int numTriangles; axTriangle_t *triangle; axTriangle_t *triangles = NULL; int numMaterials; axMaterial_t *material; axMaterial_t *materials = NULL; int numReferenceBones; axReferenceBone_t *refBone; axReferenceBone_t *refBones = NULL; int numWeights; axBoneWeight_t *axWeight; axBoneWeight_t *axWeights = NULL; md5Model_t *md5; md5Bone_t *md5Bone; vec3_t boneOrigin; quat_t boneQuat; //matrix_t boneMat; int materialIndex, oldMaterialIndex; int numRemaining; growList_t sortedTriangles; growList_t vboVertexes; growList_t vboTriangles; growList_t vboSurfaces; int numBoneReferences; int boneReferences[ MAX_BONES ]; matrix_t unrealToQuake; #define DeallocAll() Com_Dealloc( materials ); \ Com_Dealloc( points ); \ Com_Dealloc( vertexes ); \ Com_Dealloc( triangles ); \ Com_Dealloc( refBones ); \ Com_Dealloc( axWeights ); \ FreeMemStream( stream ); //MatrixSetupScale(unrealToQuake, 1, -1, 1); MatrixFromAngles( unrealToQuake, 0, 90, 0 ); stream = AllocMemStream( (byte*) buffer, bufferSize ); GetChunkHeader( stream, &chunkHeader ); // check indent again if ( Q_strnicmp( chunkHeader.ident, "ACTRHEAD", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "ACTRHEAD" ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); mod->type = MOD_MD5; mod->dataSize += sizeof( md5Model_t ); md5 = mod->md5 = (md5Model_t*) ri.Hunk_Alloc( sizeof( md5Model_t ), h_low ); // read points GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "PNTS0000", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "PNTS0000" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axPoint_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axPoint_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numPoints = chunkHeader.numData; points = (axPoint_t*) Com_Allocate( numPoints * sizeof( axPoint_t ) ); for ( i = 0, point = points; i < numPoints; i++, point++ ) { point->point[ 0 ] = MemStreamGetFloat( stream ); point->point[ 1 ] = MemStreamGetFloat( stream ); point->point[ 2 ] = MemStreamGetFloat( stream ); #if 0 // Tr3B: HACK convert from Unreal coordinate system to the Quake one MatrixTransformPoint2( unrealToQuake, point->point ); #endif } // read vertices GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "VTXW0000", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "VTXW0000" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axVertex_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axVertex_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numVertexes = chunkHeader.numData; vertexes = (axVertex_t*) Com_Allocate( numVertexes * sizeof( axVertex_t ) ); for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ ) { vertex->pointIndex = MemStreamGetShort( stream ); if ( vertex->pointIndex < 0 || vertex->pointIndex >= numPoints ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has vertex with point index out of range (%i while max %i)\n", modName, vertex->pointIndex, numPoints ); DeallocAll(); return qfalse; } vertex->unknownA = MemStreamGetShort( stream ); vertex->st[ 0 ] = MemStreamGetFloat( stream ); vertex->st[ 1 ] = MemStreamGetFloat( stream ); vertex->materialIndex = MemStreamGetC( stream ); vertex->reserved = MemStreamGetC( stream ); vertex->unknownB = MemStreamGetShort( stream ); #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: axVertex_t(%i):\n" "axVertex:pointIndex: %i\n" "axVertex:unknownA: %i\n" "axVertex::st: %f %f\n" "axVertex:materialIndex: %i\n" "axVertex:reserved: %d\n" "axVertex:unknownB: %d\n", i, vertex->pointIndex, vertex->unknownA, vertex->st[ 0 ], vertex->st[ 1 ], vertex->materialIndex, vertex->reserved, vertex->unknownB ); #endif } // read triangles GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "FACE0000", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "FACE0000" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axTriangle_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axTriangle_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numTriangles = chunkHeader.numData; triangles = (axTriangle_t*) Com_Allocate( numTriangles * sizeof( axTriangle_t ) ); for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ ) { for ( j = 0; j < 3; j++ ) //for(j = 2; j >= 0; j--) { triangle->indexes[ j ] = MemStreamGetShort( stream ); if ( triangle->indexes[ j ] >= numVertexes ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has triangle with vertex index out of range (%i while max %i)\n", modName, triangle->indexes[ j ], numVertexes ); DeallocAll(); return qfalse; } } triangle->materialIndex = MemStreamGetC( stream ); triangle->materialIndex2 = MemStreamGetC( stream ); triangle->smoothingGroups = MemStreamGetLong( stream ); } // read materials GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "MATT0000", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "MATT0000" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axMaterial_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axMaterial_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numMaterials = chunkHeader.numData; materials = (axMaterial_t*) Com_Allocate( numMaterials * sizeof( axMaterial_t ) ); for ( i = 0, material = materials; i < numMaterials; i++, material++ ) { MemStreamRead( stream, material->name, sizeof( material->name ) ); ri.Printf( PRINT_ALL, "R_LoadPSK: material name: '%s'\n", material->name ); material->shaderIndex = MemStreamGetLong( stream ); material->polyFlags = MemStreamGetLong( stream ); material->auxMaterial = MemStreamGetLong( stream ); material->auxFlags = MemStreamGetLong( stream ); material->lodBias = MemStreamGetLong( stream ); material->lodStyle = MemStreamGetLong( stream ); } for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ ) { if ( vertex->materialIndex < 0 || vertex->materialIndex >= numMaterials ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has vertex with material index out of range (%i while max %i)\n", modName, vertex->materialIndex, numMaterials ); DeallocAll(); return qfalse; } } for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ ) { if ( triangle->materialIndex < 0 || triangle->materialIndex >= numMaterials ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has triangle with material index out of range (%i while max %i)\n", modName, triangle->materialIndex, numMaterials ); DeallocAll(); return qfalse; } } // read reference bones GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "REFSKELT", 8 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "REFSKELT" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axReferenceBone_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axReferenceBone_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numReferenceBones = chunkHeader.numData; refBones = (axReferenceBone_t*) Com_Allocate( numReferenceBones * sizeof( axReferenceBone_t ) ); for ( i = 0, refBone = refBones; i < numReferenceBones; i++, refBone++ ) { MemStreamRead( stream, refBone->name, sizeof( refBone->name ) ); //ri.Printf(PRINT_ALL, "R_LoadPSK: reference bone name: '%s'\n", refBone->name); refBone->flags = MemStreamGetLong( stream ); refBone->numChildren = MemStreamGetLong( stream ); refBone->parentIndex = MemStreamGetLong( stream ); GetBone( stream, &refBone->bone ); #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: axReferenceBone_t(%i):\n" "axReferenceBone_t::name: '%s'\n" "axReferenceBone_t::flags: %i\n" "axReferenceBone_t::numChildren %i\n" "axReferenceBone_t::parentIndex: %i\n" "axReferenceBone_t::quat: %f %f %f %f\n" "axReferenceBone_t::position: %f %f %f\n" "axReferenceBone_t::length: %f\n" "axReferenceBone_t::xSize: %f\n" "axReferenceBone_t::ySize: %f\n" "axReferenceBone_t::zSize: %f\n", i, refBone->name, refBone->flags, refBone->numChildren, refBone->parentIndex, refBone->bone.quat[ 0 ], refBone->bone.quat[ 1 ], refBone->bone.quat[ 2 ], refBone->bone.quat[ 3 ], refBone->bone.position[ 0 ], refBone->bone.position[ 1 ], refBone->bone.position[ 2 ], refBone->bone.length, refBone->bone.xSize, refBone->bone.ySize, refBone->bone.zSize ); #endif } // read bone weights GetChunkHeader( stream, &chunkHeader ); if ( Q_strnicmp( chunkHeader.ident, "RAWWEIGHTS", 10 ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk indent ('%s' should be '%s')\n", modName, chunkHeader.ident, "RAWWEIGHTS" ); DeallocAll(); return qfalse; } if ( chunkHeader.dataSize != sizeof( axBoneWeight_t ) ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has wrong chunk dataSize ('%i' should be '%i')\n", modName, chunkHeader.dataSize, ( int ) sizeof( axBoneWeight_t ) ); DeallocAll(); return qfalse; } PrintChunkHeader( &chunkHeader ); numWeights = chunkHeader.numData; axWeights = (axBoneWeight_t*) Com_Allocate( numWeights * sizeof( axBoneWeight_t ) ); for ( i = 0, axWeight = axWeights; i < numWeights; i++, axWeight++ ) { axWeight->weight = MemStreamGetFloat( stream ); axWeight->pointIndex = MemStreamGetLong( stream ); axWeight->boneIndex = MemStreamGetLong( stream ); #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: axBoneWeight_t(%i):\n" "axBoneWeight_t::weight: %f\n" "axBoneWeight_t::pointIndex %i\n" "axBoneWeight_t::boneIndex: %i\n", i, axWeight->weight, axWeight->pointIndex, axWeight->boneIndex ); #endif } // // convert the model to an internal MD5 representation // md5->numBones = numReferenceBones; // calc numMeshes <number> /* numSmoothGroups = 0; for(i = 0, triangle = triangles; i < numTriangles; i++, triangle++) { if(triangle->smoothingGroups) { } } */ if ( md5->numBones < 1 ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has no bones\n", modName ); DeallocAll(); return qfalse; } if ( md5->numBones > MAX_BONES ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: '%s' has more than %i bones (%i)\n", modName, MAX_BONES, md5->numBones ); DeallocAll(); return qfalse; } //ri.Printf(PRINT_ALL, "R_LoadPSK: '%s' has %i bones\n", modName, md5->numBones); // copy all reference bones md5->bones = (md5Bone_t*) ri.Hunk_Alloc( sizeof( *md5Bone ) * md5->numBones, h_low ); for ( i = 0, md5Bone = md5->bones, refBone = refBones; i < md5->numBones; i++, md5Bone++, refBone++ ) { Q_strncpyz( md5Bone->name, refBone->name, sizeof( md5Bone->name ) ); if ( i == 0 ) { md5Bone->parentIndex = refBone->parentIndex - 1; } else { md5Bone->parentIndex = refBone->parentIndex; } //ri.Printf(PRINT_ALL, "R_LoadPSK: '%s' has bone '%s' with parent index %i\n", modName, md5Bone->name, md5Bone->parentIndex); if ( md5Bone->parentIndex >= md5->numBones ) { DeallocAll(); ri.Error( ERR_DROP, "R_LoadPSK: '%s' has bone '%s' with bad parent index %i while numBones is %i", modName, md5Bone->name, md5Bone->parentIndex, md5->numBones ); } for ( j = 0; j < 3; j++ ) { boneOrigin[ j ] = refBone->bone.position[ j ]; } // Tr3B: I have really no idea why the .psk format stores the first quaternion with inverted quats. // Furthermore only the X and Z components of the first quat are inverted ?!?! if ( i == 0 ) { boneQuat[ 0 ] = refBone->bone.quat[ 0 ]; boneQuat[ 1 ] = -refBone->bone.quat[ 1 ]; boneQuat[ 2 ] = refBone->bone.quat[ 2 ]; boneQuat[ 3 ] = refBone->bone.quat[ 3 ]; } else { boneQuat[ 0 ] = -refBone->bone.quat[ 0 ]; boneQuat[ 1 ] = -refBone->bone.quat[ 1 ]; boneQuat[ 2 ] = -refBone->bone.quat[ 2 ]; boneQuat[ 3 ] = refBone->bone.quat[ 3 ]; } VectorCopy( boneOrigin, md5Bone->origin ); //MatrixTransformPoint(unrealToQuake, boneOrigin, md5Bone->origin); QuatCopy( boneQuat, md5Bone->rotation ); //QuatClear(md5Bone->rotation); #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: md5Bone_t(%i):\n" "md5Bone_t::name: '%s'\n" "md5Bone_t::parentIndex: %i\n" "md5Bone_t::quat: %f %f %f %f\n" "md5bone_t::position: %f %f %f\n", i, md5Bone->name, md5Bone->parentIndex, md5Bone->rotation[ 0 ], md5Bone->rotation[ 1 ], md5Bone->rotation[ 2 ], md5Bone->rotation[ 3 ], md5Bone->origin[ 0 ], md5Bone->origin[ 1 ], md5Bone->origin[ 2 ] ); #endif if ( md5Bone->parentIndex >= 0 ) { vec3_t rotated; quat_t quat; md5Bone_t *parent; parent = &md5->bones[ md5Bone->parentIndex ]; QuatTransformVector( parent->rotation, md5Bone->origin, rotated ); //QuatTransformVector(md5Bone->rotation, md5Bone->origin, rotated); VectorAdd( parent->origin, rotated, md5Bone->origin ); QuatMultiply1( parent->rotation, md5Bone->rotation, quat ); QuatCopy( quat, md5Bone->rotation ); } #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: md5Bone_t(%i):\n" "md5Bone_t::name: '%s'\n" "md5Bone_t::parentIndex: %i\n" "md5Bone_t::quat: %f %f %f %f\n" "md5bone_t::position: %f %f %f\n", i, md5Bone->name, md5Bone->parentIndex, md5Bone->rotation[ 0 ], md5Bone->rotation[ 1 ], md5Bone->rotation[ 2 ], md5Bone->rotation[ 3 ], md5Bone->origin[ 0 ], md5Bone->origin[ 1 ], md5Bone->origin[ 2 ] ); #endif } Com_InitGrowList( &vboVertexes, 10000 ); for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ ) { md5Vertex_t *vboVert = (md5Vertex_t*) Com_Allocate( sizeof( *vboVert ) ); for ( j = 0; j < 3; j++ ) { vboVert->position[ j ] = points[ vertex->pointIndex ].point[ j ]; } vboVert->texCoords[ 0 ] = vertex->st[ 0 ]; vboVert->texCoords[ 1 ] = vertex->st[ 1 ]; // find number of associated weights vboVert->numWeights = 0; for ( j = 0, axWeight = axWeights; j < numWeights; j++, axWeight++ ) { if ( axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f ) { vboVert->numWeights++; } } if ( vboVert->numWeights > MAX_WEIGHTS ) { DeallocAll(); ri.Error( ERR_DROP, "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'", i, vboVert->numWeights, MAX_WEIGHTS, modName ); //ri.Printf(PRINT_WARNING, "R_LoadPSK: vertex %i requires more weights %i than the maximum of %i in model '%s'\n", i, vboVert->numWeights, MAX_WEIGHTS, modName); } for ( j = 0, axWeight = axWeights, k = 0; j < numWeights; j++, axWeight++ ) { if ( axWeight->pointIndex == vertex->pointIndex && axWeight->weight > 0.0f ) { vboVert->boneIndexes[ k ] = axWeight->boneIndex; vboVert->boneWeights[ k ] = axWeight->weight; k++; } } Com_AddToGrowList( &vboVertexes, vboVert ); } ClearBounds( md5->bounds[ 0 ], md5->bounds[ 1 ] ); for ( i = 0, vertex = vertexes; i < numVertexes; i++, vertex++ ) { AddPointToBounds( points[ vertex->pointIndex ].point, md5->bounds[ 0 ], md5->bounds[ 1 ] ); } #if 0 ri.Printf( PRINT_ALL, "R_LoadPSK: AABB (%i %i %i) (%i %i %i)\n", ( int ) md5->bounds[ 0 ][ 0 ], ( int ) md5->bounds[ 0 ][ 1 ], ( int ) md5->bounds[ 0 ][ 2 ], ( int ) md5->bounds[ 1 ][ 0 ], ( int ) md5->bounds[ 1 ][ 1 ], ( int ) md5->bounds[ 1 ][ 2 ] ); #endif // sort triangles qsort( triangles, numTriangles, sizeof( axTriangle_t ), CompareTrianglesByMaterialIndex ); Com_InitGrowList( &sortedTriangles, 1000 ); for ( i = 0, triangle = triangles; i < numTriangles; i++, triangle++ ) { skelTriangle_t *sortTri = (skelTriangle_t*) Com_Allocate( sizeof( *sortTri ) ); for ( j = 0; j < 3; j++ ) { sortTri->indexes[ j ] = triangle->indexes[ j ]; sortTri->vertexes[ j ] = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, triangle->indexes[ j ] ); } sortTri->referenced = qfalse; Com_AddToGrowList( &sortedTriangles, sortTri ); } // calc tangent spaces #if 1 { md5Vertex_t *v0, *v1, *v2; const float *p0, *p1, *p2; const float *t0, *t1, *t2; vec3_t tangent; vec3_t binormal; vec3_t normal; for ( j = 0; j < vboVertexes.currentElements; j++ ) { v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j ); VectorClear( v0->tangent ); VectorClear( v0->binormal ); VectorClear( v0->normal ); } for ( j = 0; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *tri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j ); v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 0 ] ); v1 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 1 ] ); v2 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ 2 ] ); p0 = v0->position; p1 = v1->position; p2 = v2->position; t0 = v0->texCoords; t1 = v1->texCoords; t2 = v2->texCoords; #if 1 R_CalcTangentSpace( tangent, binormal, normal, p0, p1, p2, t0, t1, t2 ); #else R_CalcNormalForTriangle( normal, p0, p1, p2 ); R_CalcTangentsForTriangle( tangent, binormal, p0, p1, p2, t0, t1, t2 ); #endif for ( k = 0; k < 3; k++ ) { float *v; v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, tri->indexes[ k ] ); v = v0->tangent; VectorAdd( v, tangent, v ); v = v0->binormal; VectorAdd( v, binormal, v ); v = v0->normal; VectorAdd( v, normal, v ); } } for ( j = 0; j < vboVertexes.currentElements; j++ ) { v0 = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j ); VectorNormalize( v0->tangent ); VectorNormalize( v0->binormal ); VectorNormalize( v0->normal ); } } #else { float bb, s, t; vec3_t bary; vec3_t faceNormal; md5Vertex_t *dv[ 3 ]; for ( j = 0; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *tri = Com_GrowListElement( &sortedTriangles, j ); dv[ 0 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 0 ] ); dv[ 1 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 1 ] ); dv[ 2 ] = Com_GrowListElement( &vboVertexes, tri->indexes[ 2 ] ); R_CalcNormalForTriangle( faceNormal, dv[ 0 ]->position, dv[ 1 ]->position, dv[ 2 ]->position ); // calculate barycentric basis for the triangle bb = ( dv[ 1 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 2 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ) - ( dv[ 2 ]->texCoords[ 0 ] - dv[ 0 ]->texCoords[ 0 ] ) * ( dv[ 1 ]->texCoords[ 1 ] - dv[ 0 ]->texCoords[ 1 ] ); if ( fabs( bb ) < 0.00000001f ) { continue; } // do each vertex for ( k = 0; k < 3; k++ ) { // calculate s tangent vector s = dv[ k ]->texCoords[ 0 ] + 10.0f; t = dv[ k ]->texCoords[ 1 ]; bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb; dv[ k ]->tangent[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ]; dv[ k ]->tangent[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ]; dv[ k ]->tangent[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ]; VectorSubtract( dv[ k ]->tangent, dv[ k ]->position, dv[ k ]->tangent ); VectorNormalize( dv[ k ]->tangent ); // calculate t tangent vector (binormal) s = dv[ k ]->texCoords[ 0 ]; t = dv[ k ]->texCoords[ 1 ] + 10.0f; bary[ 0 ] = ( ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) - ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 1 ] = ( ( dv[ 2 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) - ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 2 ]->texCoords[ 1 ] - t ) ) / bb; bary[ 2 ] = ( ( dv[ 0 ]->texCoords[ 0 ] - s ) * ( dv[ 1 ]->texCoords[ 1 ] - t ) - ( dv[ 1 ]->texCoords[ 0 ] - s ) * ( dv[ 0 ]->texCoords[ 1 ] - t ) ) / bb; dv[ k ]->binormal[ 0 ] = bary[ 0 ] * dv[ 0 ]->position[ 0 ] + bary[ 1 ] * dv[ 1 ]->position[ 0 ] + bary[ 2 ] * dv[ 2 ]->position[ 0 ]; dv[ k ]->binormal[ 1 ] = bary[ 0 ] * dv[ 0 ]->position[ 1 ] + bary[ 1 ] * dv[ 1 ]->position[ 1 ] + bary[ 2 ] * dv[ 2 ]->position[ 1 ]; dv[ k ]->binormal[ 2 ] = bary[ 0 ] * dv[ 0 ]->position[ 2 ] + bary[ 1 ] * dv[ 1 ]->position[ 2 ] + bary[ 2 ] * dv[ 2 ]->position[ 2 ]; VectorSubtract( dv[ k ]->binormal, dv[ k ]->position, dv[ k ]->binormal ); VectorNormalize( dv[ k ]->binormal ); // calculate the normal as cross product N=TxB #if 0 CrossProduct( dv[ k ]->tangent, dv[ k ]->binormal, dv[ k ]->normal ); VectorNormalize( dv[ k ]->normal ); // Gram-Schmidt orthogonalization process for B // compute the cross product B=NxT to obtain // an orthogonal basis CrossProduct( dv[ k ]->normal, dv[ k ]->tangent, dv[ k ]->binormal ); if ( DotProduct( dv[ k ]->normal, faceNormal ) < 0 ) { VectorInverse( dv[ k ]->normal ); //VectorInverse(dv[k]->tangent); //VectorInverse(dv[k]->binormal); } #else VectorAdd( dv[ k ]->normal, faceNormal, dv[ k ]->normal ); #endif } } #if 1 for ( j = 0; j < vboVertexes.currentElements; j++ ) { dv[ 0 ] = Com_GrowListElement( &vboVertexes, j ); //VectorNormalize(dv[0]->tangent); //VectorNormalize(dv[0]->binormal); VectorNormalize( dv[ 0 ]->normal ); } #endif } #endif #if 0 { md5Vertex_t *v0, *v1; // do another extra smoothing for normals to avoid flat shading for ( j = 0; j < vboVertexes.currentElements; j++ ) { v0 = Com_GrowListElement( &vboVertexes, j ); for ( k = 0; k < vboVertexes.currentElements; k++ ) { if ( j == k ) { continue; } v1 = Com_GrowListElement( &vboVertexes, k ); if ( VectorCompare( v0->position, v1->position ) ) { VectorAdd( v0->position, v1->normal, v0->normal ); } } VectorNormalize( v0->normal ); } } #endif // split the surfaces into VBO surfaces by the maximum number of GPU vertex skinning bones Com_InitGrowList( &vboSurfaces, 10 ); materialIndex = oldMaterialIndex = -1; for ( i = 0; i < numTriangles; i++ ) { triangle = &triangles[ i ]; materialIndex = triangle->materialIndex; if ( materialIndex != oldMaterialIndex ) { oldMaterialIndex = materialIndex; numRemaining = sortedTriangles.currentElements - i; while ( numRemaining ) { numBoneReferences = 0; Com_Memset( boneReferences, 0, sizeof( boneReferences ) ); Com_InitGrowList( &vboTriangles, 1000 ); for ( j = i; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *sortTri; triangle = &triangles[ j ]; materialIndex = triangle->materialIndex; if ( materialIndex != oldMaterialIndex ) { continue; } sortTri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j ); if ( sortTri->referenced ) { continue; } if ( AddTriangleToVBOTriangleList( &vboTriangles, sortTri, &numBoneReferences, boneReferences ) ) { sortTri->referenced = qtrue; } } for ( j = 0; j < MAX_BONES; j++ ) { if ( boneReferences[ j ] > 0 ) { ri.Printf( PRINT_ALL, "R_LoadPSK: referenced bone: '%s'\n", ( j < numReferenceBones ) ? refBones[ j ].name : NULL ); } } if ( !vboTriangles.currentElements ) { ri.Printf( PRINT_WARNING, "R_LoadPSK: could not add triangles to a remaining VBO surface for model '%s'\n", modName ); break; } // FIXME skinIndex AddSurfaceToVBOSurfacesList2( &vboSurfaces, &vboTriangles, &vboVertexes, md5, vboSurfaces.currentElements, materials[ oldMaterialIndex ].name, numBoneReferences, boneReferences ); numRemaining -= vboTriangles.currentElements; Com_DestroyGrowList( &vboTriangles ); } } } for ( j = 0; j < sortedTriangles.currentElements; j++ ) { skelTriangle_t *sortTri = (skelTriangle_t*) Com_GrowListElement( &sortedTriangles, j ); Com_Dealloc( sortTri ); } Com_DestroyGrowList( &sortedTriangles ); for ( j = 0; j < vboVertexes.currentElements; j++ ) { md5Vertex_t *v = (md5Vertex_t*) Com_GrowListElement( &vboVertexes, j ); Com_Dealloc( v ); } Com_DestroyGrowList( &vboVertexes ); // move VBO surfaces list to hunk md5->numVBOSurfaces = vboSurfaces.currentElements; md5->vboSurfaces = (srfVBOMD5Mesh_t**) ri.Hunk_Alloc( md5->numVBOSurfaces * sizeof( *md5->vboSurfaces ), h_low ); for ( i = 0; i < md5->numVBOSurfaces; i++ ) { md5->vboSurfaces[ i ] = ( srfVBOMD5Mesh_t * ) Com_GrowListElement( &vboSurfaces, i ); } Com_DestroyGrowList( &vboSurfaces ); FreeMemStream( stream ); Com_Dealloc( points ); Com_Dealloc( vertexes ); Com_Dealloc( triangles ); Com_Dealloc( materials ); ri.Printf( PRINT_DEVELOPER, "%i VBO surfaces created for PSK model '%s'\n", md5->numVBOSurfaces, modName ); return qtrue; }
void AddTriangleModels(entity_t * e) { int num, frame, castShadows, recvShadows, spawnFlags; entity_t *e2; const char *targetName; const char *target, *model, *value; char shader[MAX_QPATH]; shaderInfo_t *celShader; float temp, baseLightmapScale, lightmapScale; float shadeAngle; int lightmapSampleSize; vec3_t origin, scale, angles; matrix_t rotation, rotationScaled, transform; epair_t *ep; remap_t *remap, *remap2; char *split; /* note it */ Sys_FPrintf(SYS_VRB, "--- AddTriangleModels ---\n"); /* get current brush entity targetname */ if(e == entities) targetName = ""; else { targetName = ValueForKey(e, "name"); /* misc_model entities target non-worldspawn brush model entities */ if(targetName[0] == '\0') return; } /* get lightmap scale */ /* vortex: added _ls key (short name of lightmapscale) */ baseLightmapScale = 0.0f; if(strcmp("", ValueForKey(e, "lightmapscale")) || strcmp("", ValueForKey(e, "_lightmapscale")) || strcmp("", ValueForKey(e, "_ls"))) { baseLightmapScale = FloatForKey(e, "lightmapscale"); if(baseLightmapScale <= 0.0f) baseLightmapScale = FloatForKey(e, "_lightmapscale"); if(baseLightmapScale <= 0.0f) baseLightmapScale = FloatForKey(e, "_ls"); if(baseLightmapScale < 0.0f) baseLightmapScale = 0.0f; if(baseLightmapScale > 0.0f) Sys_Printf("World Entity has lightmap scale of %.4f\n", baseLightmapScale); } /* walk the entity list */ for(num = 1; num < numEntities; num++) { /* get e2 */ e2 = &entities[num]; /* convert misc_models into raw geometry */ if(Q_stricmp("misc_model", ValueForKey(e2, "classname"))) continue; /* ydnar: added support for md3 models on non-worldspawn models */ target = ValueForKey(e2, "target"); if(strcmp(target, targetName)) continue; /* get model name */ model = ValueForKey(e2, "model"); if(model[0] == '\0') { Sys_Printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0], (int)origin[1], (int)origin[2]); continue; } /* get model frame */ frame = IntForKey(e2, "_frame"); /* worldspawn (and func_groups) default to cast/recv shadows in worldspawn group */ if(e == entities) { castShadows = WORLDSPAWN_CAST_SHADOWS; recvShadows = WORLDSPAWN_RECV_SHADOWS; } /* other entities don't cast any shadows, but recv worldspawn shadows */ else { castShadows = ENTITY_CAST_SHADOWS; recvShadows = ENTITY_RECV_SHADOWS; } /* get explicit shadow flags */ GetEntityShadowFlags(e2, e, &castShadows, &recvShadows); /* get spawnflags */ spawnFlags = IntForKey(e2, "spawnflags"); /* Tr3B: added clipModel option */ spawnFlags |= (IntForKey(e2, "clipModel") > 0) ? 2 : 0; /* Tr3B: added forceMeta option */ spawnFlags |= (IntForKey(e2, "forceMeta") > 0) ? 4 : 0; /* get origin */ GetVectorForKey(e2, "origin", origin); VectorSubtract(origin, e->origin, origin); /* offset by parent */ /* get "angle" (yaw) or "angles" (pitch yaw roll) */ MatrixIdentity(rotation); angles[0] = angles[1] = angles[2] = 0.0f; value = ValueForKey(e2, "angle"); if(value[0] != '\0') { angles[1] = atof(value); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e2, "angles"); if(value[0] != '\0') { sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]); MatrixFromAngles(rotation, angles[PITCH], angles[YAW], angles[ROLL]); } value = ValueForKey(e2, "rotation"); if(value[0] != '\0') { sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2], &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]); } /* get scale */ scale[0] = scale[1] = scale[2] = 1.0f; temp = FloatForKey(e2, "modelscale"); if(temp != 0.0f) scale[0] = scale[1] = scale[2] = temp; value = ValueForKey(e2, "modelscale_vec"); if(value[0] != '\0') sscanf(value, "%f %f %f", &scale[0], &scale[1], &scale[2]); MatrixCopy(rotation, rotationScaled); MatrixMultiplyScale(rotationScaled, scale[0], scale[1], scale[2]); /* set transform matrix */ MatrixIdentity(transform); MatrixSetupTransformFromRotation(transform, rotationScaled, origin); /* get shader remappings */ remap = NULL; for(ep = e2->epairs; ep != NULL; ep = ep->next) { /* look for keys prefixed with "_remap" */ if(ep->key != NULL && ep->value != NULL && ep->key[0] != '\0' && ep->value[0] != '\0' && !Q_strncasecmp(ep->key, "_remap", 6)) { /* create new remapping */ remap2 = remap; remap = safe_malloc(sizeof(*remap)); remap->next = remap2; strcpy(remap->from, ep->value); /* split the string */ split = strchr(remap->from, ';'); if(split == NULL) { Sys_Printf("WARNING: Shader _remap key found in misc_model without a ; character\n"); free(remap); remap = remap2; continue; } /* store the split */ *split = '\0'; strcpy(remap->to, (split + 1)); /* note it */ //% Sys_FPrintf( SYS_VRB, "Remapping %s to %s\n", remap->from, remap->to ); } } /* ydnar: cel shader support */ value = ValueForKey(e2, "_celshader"); if(value[0] == '\0') value = ValueForKey(&entities[0], "_celshader"); if(value[0] != '\0') { sprintf(shader, "textures/%s", value); celShader = ShaderInfoForShader(shader); } else celShader = NULL; /* jal : entity based _samplesize */ lightmapSampleSize = 0; if(strcmp("", ValueForKey(e2, "_lightmapsamplesize"))) lightmapSampleSize = IntForKey(e2, "_lightmapsamplesize"); else if(strcmp("", ValueForKey(e2, "_samplesize"))) lightmapSampleSize = IntForKey(e2, "_samplesize"); if(lightmapSampleSize < 0) lightmapSampleSize = 0; if(lightmapSampleSize > 0.0f) Sys_Printf("misc_model has lightmap sample size of %.d\n", lightmapSampleSize); /* get lightmap scale */ /* vortex: added _ls key (short name of lightmapscale) */ lightmapScale = 0.0f; if(strcmp("", ValueForKey(e2, "lightmapscale")) || strcmp("", ValueForKey(e2, "_lightmapscale")) || strcmp("", ValueForKey(e2, "_ls"))) { lightmapScale = FloatForKey(e2, "lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e2, "_lightmapscale"); if(lightmapScale <= 0.0f) lightmapScale = FloatForKey(e2, "_ls"); if(lightmapScale < 0.0f) lightmapScale = 0.0f; if(lightmapScale > 0.0f) Sys_Printf("misc_model has lightmap scale of %.4f\n", lightmapScale); } /* jal : entity based _shadeangle */ shadeAngle = 0.0f; if(strcmp("", ValueForKey(e2, "_shadeangle"))) shadeAngle = FloatForKey(e2, "_shadeangle"); /* vortex' aliases */ else if(strcmp("", ValueForKey(mapEnt, "_smoothnormals"))) shadeAngle = FloatForKey(mapEnt, "_smoothnormals"); else if(strcmp("", ValueForKey(mapEnt, "_sn"))) shadeAngle = FloatForKey(mapEnt, "_sn"); else if(strcmp("", ValueForKey(mapEnt, "_smooth"))) shadeAngle = FloatForKey(mapEnt, "_smooth"); if(shadeAngle < 0.0f) shadeAngle = 0.0f; if(shadeAngle > 0.0f) Sys_Printf("misc_model has shading angle of %.4f\n", shadeAngle); /* insert the model */ InsertModel((char *)model, frame, transform, rotation, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle); /* free shader remappings */ while(remap != NULL) { remap2 = remap->next; free(remap); remap = remap2; } } }
static int vmatrix_MatrixFromAngles (lua_State *L) { MatrixFromAngles(luaL_checkangle(L, 1), luaL_checkvmatrix(L, 2)); return 0; }