/* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2007 Peter Mackay and Chris Swindle. 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. */ // r_main.c extern "C" { #include "../../quakedef.h" float TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal); } //includes #include "gu_hlmdl.h" #include #include #include "../clipping.hpp" using namespace quake; //prototypes extern "C" void V_CalcBlend (void); void Fog_SetupFrame (bool worldgeom); void Fog_EnableGFog (void); void Fog_DisableGFog (void); void R_DrawDecals (void); void R_RenderDecals (void); void R_MarkLeaves (void); // void QMB_LetItRain(void); void QMB_LaserSight (void); void VID_SetPaletteH2(); void VID_SetPaletteTX(); // globals const float piconst = GU_PI / 180.0f; entity_t r_worldentity; entity_t *currententity; qboolean envmap; qboolean mirror; // view origin vec3_t vup; vec3_t vpn; vec3_t vright; vec3_t r_origin; vec3_t modelorg, r_entorigin; int r_visframecount; // bumped when going to a new PVS int r_framecount; // used for dlight push checking int c_brush_polys, c_alias_polys, c_md3_polys; int currenttexture = -1; // to avoid unnecessary texture sets int cnttextures[2] = {-1, -1}; // cached int particletexture; // little dot for particles int playertextures; // up to 16 color translated skins int mirrortexturenum; // quake texturenum, not gltexturenum int game_fps; // should probably move this somewhere less.. lame mplane_t *mirror_plane; mplane_t frustum[4]; // screen size info refdef_t r_refdef; mleaf_t *r_viewleaf; mleaf_t *r_oldviewleaf; texture_t *r_notexture_mip; bool fixlight; bool alphafunc2; bool alphafunc; ScePspFMatrix4 r_world_matrix; ScePspFMatrix4 r_base_world_matrix; ScePspFMatrix4 md3mult; int d_lightstylevalue[256]; // 8.8 fraction of base light value cvar_t r_partalpha = {"r_partalpha", "0.8",qtrue}; cvar_t r_norefresh = {"r_norefresh", "0"}; cvar_t r_drawentities = {"r_drawentities", "1"}; cvar_t r_drawviewmodel = {"r_drawviewmodel", "1"}; cvar_t r_speeds = {"r_speeds", "0"}; cvar_t r_fullbright = {"r_fullbright", "0"}; cvar_t r_lightmap = {"r_lightmap", "0"}; cvar_t r_shadows = {"r_shadows", "0"}; cvar_t r_mirroralpha = {"r_mirroralpha", "1",qtrue}; cvar_t r_wateralpha = {"r_wateralpha", "0.6",qtrue}; cvar_t r_vsync = {"r_vsync", "0",qtrue}; cvar_t r_farclip = {"r_farclip", "4096"}; //far cliping for q3 models cvar_t r_loadq3models = {"r_loadq3models", "0",qtrue}; //replace player model to q3 player cvar_t cl_loadmapcfg = {"cl_loadmapcfg", "0",qtrue}; //Load individual cfg for map cvar_t r_restexf = {"r_restexf", "0",qtrue}; //texture resampler setup cvar_t r_texcompr = {"r_texcompr", "5",qtrue}; //texture compression setup (default DXT5) warning DXT1 conflicted with switches palettes cvar_t r_maxrange = {"r_maxrange", "4096"}; //render distance cvar_t r_skydis = {"r_skydis", "2560",qtrue}; cvar_t r_skyfog = {"r_skyfog", "1",qtrue}; cvar_t r_caustics = {"r_caustics", "1",qtrue}; cvar_t r_detail = {"r_detail", "1",qtrue}; cvar_t r_detail_mipmaps = {"r_detail_mipmaps", "1",qtrue}; cvar_t r_detail_mipmaps_func = {"r_detail_mipmaps_func", "2",qtrue}; cvar_t r_detail_mipmaps_bias = {"r_detail_mipmaps_bias", "-6",qtrue}; cvar_t r_asynch = {"r_asynch", "0"}; cvar_t r_i_model_animation = {"r_i_model_animation", "1",qtrue}; // Toggle smooth model animation cvar_t r_i_model_transform = {"r_i_model_transform", "1",qtrue}; // Toggle smooth model movement cvar_t r_mipmaps = {"r_mipmaps", "1",qtrue}; cvar_t r_mipmaps_func = {"r_mipmaps_func", "2",qtrue}; // Adjust mip map calculations cvar_t r_mipmaps_bias = {"r_mipmaps_bias", "-7",qtrue}; // Adjust mip map bias cvar_t r_retro = {"r_retro", "0",qtrue}; // dr_mabuse1981: "retro filter". cvar_t r_dynamic = {"r_dynamic", "0"}; cvar_t r_novis = {"r_novis", "0"}; cvar_t r_tex_scale_down = {"r_tex_scale_down", "1",qtrue}; cvar_t r_particles_simple = {"r_particles_simple", "0",qtrue}; cvar_t gl_keeptjunctions = {"gl_keeptjunctions", "0"}; cvar_t r_waterripple = {"r_waterripple", "2",qtrue}; cvar_t r_waterwarp = {"r_waterwarp", "1",qtrue}; cvar_t r_fastsky = {"r_fastsky", "1",qtrue}; cvar_t r_skycolor = {"r_skycolor", "64 64 70",qtrue}; cvar_t r_showbboxes = {"r_showbboxes", "0"}; cvar_t r_showbboxes_full = {"r_showbboxes_full", "0",qtrue}; cvar_t r_showtris = {"r_showtris", "0"}; cvar_t r_showtris_full = {"r_showtris_full", "0",qtrue}; cvar_t r_polyblend = {"r_polyblend", "1",qtrue}; cvar_t r_skyfogblend = {"r_skyfogblend", "0.6", qtrue}; //QMB cvar_t r_explosiontype = {"r_explosiontype", "0",qtrue}; cvar_t r_laserpoint = {"r_laserpoint", "0",qtrue}; cvar_t r_part_explosions = {"r_part_explosions", "1",qtrue}; cvar_t r_part_trails = {"r_part_trails", "1",qtrue}; cvar_t r_part_sparks = {"r_part_sparks", "1",qtrue}; cvar_t r_part_spikes = {"r_part_spikes", "1",qtrue}; cvar_t r_part_gunshots = {"r_part_gunshots", "1",qtrue}; cvar_t r_part_blood = {"r_part_blood", "1",qtrue}; cvar_t r_part_telesplash = {"r_part_telesplash", "1",qtrue}; cvar_t r_part_blobs = {"r_part_blobs", "1",qtrue}; cvar_t r_part_lavasplash = {"r_part_lavasplash", "1",qtrue}; cvar_t r_part_flames = {"r_part_flames", "1",qtrue}; cvar_t r_part_lightning = {"r_part_lightning", "1",qtrue}; cvar_t r_part_flies = {"r_part_flies", "1",qtrue}; cvar_t r_part_muzzleflash = {"r_part_muzzleflash", "1",qtrue}; cvar_t r_flametype = {"r_flametype", "2",qtrue}; //Shpuld cvar_t r_model_brightness = { "r_model_brightness", "1", qtrue}; // Toggle high brightness model lighting //cypress cvar_t r_runqmbparticles = {"r_runqmbparticles", "1", qtrue}; extern cvar_t cl_maxfps; extern cvar_t scr_fov_viewmodel; bool modelIsArm (char *m_name) { if (!strcmp (m_name, "progs/ai/zal.mdl") || !strcmp (m_name, "progs/ai/zar.mdl") || !strcmp (m_name, "progs/ai/bzal.mdl") || !strcmp (m_name, "progs/ai/bzar.mdl") || !strcmp (m_name, "progs/ai/zalc.mdl") || !strcmp (m_name, "progs/ai/zarc.mdl")) return true; return false; } bool modelIsHead (char *m_name) { if (!strcmp (m_name, "progs/ai/zh.mdl") || !strcmp (m_name, "progs/ai/bzh.mdl") || !strcmp (m_name, "progs/ai/zhc.mdl")) return true; return false; } bool modelIsBody (char *m_name) { if (!strcmp (m_name, "progs/ai/zb.mdl") || !strcmp (m_name, "progs/ai/bzb.mdl") || !strcmp (m_name, "progs/ai/zbc.mdl")) return true; return false; } /* ================ ConvertMatrix By Crow_bar for MD3 ================ */ void ConvertMatrix(float *a, float *b) { for (int i = 0; i < 16; i++) a[i] = b[i]; } /* ============= R_RotateForTagEntity ============= */ void R_RotateForTagEntity (tagentity_t *tagent, md3tag_t *tag, float *m) { int i; float lerpfrac, timepassed; // positional interpolation timepassed = cl.time - tagent->tag_translate_start_time; if (tagent->tag_translate_start_time == 0 || timepassed > 1) { tagent->tag_translate_start_time = cl.time; VectorCopy (tag->pos, tagent->tag_pos1); VectorCopy (tag->pos, tagent->tag_pos2); } if (!VectorCompare(tag->pos, tagent->tag_pos2)) { tagent->tag_translate_start_time = cl.time; VectorCopy (tagent->tag_pos2, tagent->tag_pos1); VectorCopy (tag->pos, tagent->tag_pos2); lerpfrac = 0; } else { lerpfrac = timepassed / 0.1; if (cl.paused || lerpfrac > 1) lerpfrac = 1; } VectorInterpolate (tagent->tag_pos1, lerpfrac, tagent->tag_pos2, m + 12); m[15] = 1; for (i=0 ; i<3 ; i++) { // orientation interpolation (Euler angles, yuck!) timepassed = cl.time - tagent->tag_rotate_start_time[i]; if (tagent->tag_rotate_start_time[i] == 0 || timepassed > 1) { tagent->tag_rotate_start_time[i] = cl.time; VectorCopy (tag->rot[i], tagent->tag_rot1[i]); VectorCopy (tag->rot[i], tagent->tag_rot2[i]); } if (!VectorCompare(tag->rot[i], tagent->tag_rot2[i])) { tagent->tag_rotate_start_time[i] = cl.time; VectorCopy (tagent->tag_rot2[i], tagent->tag_rot1[i]); VectorCopy (tag->rot[i], tagent->tag_rot2[i]); lerpfrac = 0; } else { lerpfrac = timepassed / 0.1; if (cl.paused || lerpfrac > 1) lerpfrac = 1; } VectorInterpolate (tagent->tag_rot1[i], lerpfrac, tagent->tag_rot2[i], m + i*4); m[i*4+3] = 0; } } /* ============= R_RotateForViewEntity ============= */ void R_RotateForViewEntity (entity_t *ent) { // Translate. const ScePspFVector3 translation = { ent->origin[0], ent->origin[1], ent->origin[2] }; sceGumTranslate(&translation); // Rotate. const ScePspFVector3 rotation = { ent->angles[ROLL] * piconst, -ent->angles[PITCH] * piconst, ent->angles[YAW] * piconst }; sceGumRotateZYX(&rotation); } /* ================= R_FrustumCheckBox Returns 0 if box completely inside frustum Returns +N with intersected planes count as N Returns -1 when completely outside frustum ================= */ int R_FrustumCheckBox (vec3_t mins, vec3_t maxs) { int i, res; int intersections = 0; for (i=0 ; i<4 ; i++) { res = BoxOnPlaneSide (mins, maxs, &frustum[i]); if (res == 2) return -1; if (res == 3) ++intersections; } return intersections; } /* ================= R_FrustumCheckSphere ================= */ int R_FrustumCheckSphere (vec3_t centre, float radius) { int i, res; mplane_t *p; int intersections = 0; for (i=0, p=frustum ; i<4 ; i++, p++) { res = PlaneDiff(centre, p); if (res <= -radius) return -1; if (res < radius) ++intersections; } return intersections; } /* ================= R_CullBox Returns true if the box is completely outside the frustom ================= */ int R_CullBox (vec3_t mins, vec3_t maxs) { int result = 1; // Default to "all inside". int i; for (i=0 ; i<4 ; i++) { const int plane_result = BoxOnPlaneSide(mins, maxs, &frustum[i]); if (plane_result == 2) { return 2; } else if (plane_result == 3) { result = 3; } } return result; } /* ================= R_CullSphere Returns true if the sphere is completely outside the frustum ================= */ qboolean R_CullSphere (vec3_t centre, float radius) { int i; mplane_t *p; for (i=0, p=frustum ; i<4 ; i++, p++) { if (PlaneDiff(centre, p) <= -radius) return qtrue; } return qfalse; } /* ============= R_RotateForEntity ============= */ void R_RotateForEntity (entity_t *e, int shadow, unsigned char scale) { // Translate. const ScePspFVector3 translation = { e->origin[0], e->origin[1], e->origin[2] }; sceGumTranslate(&translation); // Rotate. sceGumRotateZ(e->angles[YAW] * (GU_PI / 180.0f)); if (shadow == 0) { sceGumRotateY (-e->angles[PITCH] * (GU_PI / 180.0f)); sceGumRotateX (e->angles[ROLL] * (GU_PI / 180.0f)); } // Scale. if (scale != ENTSCALE_DEFAULT) { float scalefactor = ENTSCALE_DECODE(scale); const ScePspFVector3 scale = { scalefactor, scalefactor, scalefactor }; sceGumScale(&scale); } sceGumUpdateMatrix(); } /* ============= R_InterpolateEntity was R_BlendedRotateForEntity fenix@io.com: model transform interpolation modified by blubswillrule //fixme (come back and fix this once we can test on psp and view the true issue with interpolation) ============= */ void R_InterpolateEntity(entity_t *e, int shadow) // Tomaz - New Shadow { float timepassed; float blend; vec3_t deltaVec; int i; // positional interpolation timepassed = realtime - e->translate_start_time; //notes to self (blubs) //-Added this method, and commented out the check for r_i_model_transforms.value //tried the snapping interpolation, though it worked, it was still a bit jittery... //problem with linear interpolation is we don't know the exact time it should take to move from origin1 to origin2... //looks like the rotation interpolation doesn't work all that great either, rotation could benefit from the snapping interpolation that I use //if I get this method to work well, make sure we go back and check for r_i_model_transforms again, (because vmodel and other models that don't use interpolation) //probably go back and edit animations too as I redo the last 2 textures.. if (e->translate_start_time == 0 || timepassed > 1) { e->translate_start_time = realtime; VectorCopy (e->origin, e->origin1); VectorCopy (e->origin, e->origin2); } //our origin has been updated if (!VectorCompare (e->origin, e->origin2)) { e->translate_start_time = realtime; VectorCopy (e->origin2, e->origin1); VectorCopy (e->origin, e->origin2); blend = 0; } else { blend = timepassed / 0.4;//0.1 not sure what this value should be... //technically this value should be the total amount of time that we take from 1 position to the next, it's practically how long it should take us to go from one location to the next... if (cl.paused || blend > 1) blend = 0; } VectorSubtract (e->origin2, e->origin1, deltaVec); // Translate. const ScePspFVector3 translation = { e->origin[0] + (blend * deltaVec[0]), e->origin[1] + (blend * deltaVec[1]), e->origin[2] + (blend * deltaVec[2]) }; sceGumTranslate(&translation); // orientation interpolation (Euler angles, yuck!) timepassed = realtime - e->rotate_start_time; if (e->rotate_start_time == 0 || timepassed > 1) { e->rotate_start_time = realtime; VectorCopy (e->angles, e->angles1); VectorCopy (e->angles, e->angles2); } if (!VectorCompare (e->angles, e->angles2)) { e->rotate_start_time = realtime; VectorCopy (e->angles2, e->angles1); VectorCopy (e->angles, e->angles2); blend = 0; } else { blend = timepassed / 0.1; if (cl.paused || blend > 1) blend = 1; } VectorSubtract (e->angles2, e->angles1, deltaVec); // always interpolate along the shortest path for (i = 0; i < 3; i++) { if (deltaVec[i] > 180) { deltaVec[i] -= 360; } else if (deltaVec[i] < -180) { deltaVec[i] += 360; } } // Rotate. sceGumRotateZ((e->angles1[YAW] + ( blend * deltaVec[YAW])) * (GU_PI / 180.0f)); if (shadow == 0) { sceGumRotateY ((-e->angles1[PITCH] + (-blend * deltaVec[PITCH])) * (GU_PI / 180.0f)); sceGumRotateX ((e->angles1[ROLL] + ( blend * deltaVec[ROLL])) * (GU_PI / 180.0f)); } sceGumUpdateMatrix(); } /* ============= R_BlendedRotateForEntity fenix@io.com: model transform interpolation ============= */ void R_BlendedRotateForEntity (entity_t *e, int shadow, unsigned char scale) // Tomaz - New Shadow { float timepassed; float blend; vec3_t d; int i; // positional interpolation timepassed = realtime - e->translate_start_time; if (e->translate_start_time == 0 || timepassed > 1) { e->translate_start_time = realtime; VectorCopy (e->origin, e->origin1); VectorCopy (e->origin, e->origin2); } if (!VectorCompare (e->origin, e->origin2)) { e->translate_start_time = realtime; VectorCopy (e->origin2, e->origin1); VectorCopy (e->origin, e->origin2); blend = 0; } else { blend = timepassed / 0.1; if (cl.paused || blend > 1) blend = 0; } VectorSubtract (e->origin2, e->origin1, d); // Translate. const ScePspFVector3 translation = { e->origin[0] + (blend * d[0]), e->origin[1] + (blend * d[1]), e->origin[2] + (blend * d[2]) }; sceGumTranslate(&translation); // Scale. if (scale != ENTSCALE_DEFAULT) { float scalefactor = ENTSCALE_DECODE(scale); const ScePspFVector3 scale = { scalefactor, scalefactor, scalefactor }; sceGumScale(&scale); } // orientation interpolation (Euler angles, yuck!) timepassed = realtime - e->rotate_start_time; if (e->rotate_start_time == 0 || timepassed > 1) { e->rotate_start_time = realtime; VectorCopy (e->angles, e->angles1); VectorCopy (e->angles, e->angles2); } if (!VectorCompare (e->angles, e->angles2)) { e->rotate_start_time = realtime; VectorCopy (e->angles2, e->angles1); VectorCopy (e->angles, e->angles2); blend = 0; } else { blend = timepassed / 0.1; if (cl.paused || blend > 1) blend = 1; } VectorSubtract (e->angles2, e->angles1, d); // always interpolate along the shortest path for (i = 0; i < 3; i++) { if (d[i] > 180) { d[i] -= 360; } else if (d[i] < -180) { d[i] += 360; } } // Rotate. sceGumRotateZ((e->angles1[YAW] + ( blend * d[YAW])) * (GU_PI / 180.0f)); if (shadow == 0) { sceGumRotateY ((-e->angles1[PITCH] + (-blend * d[PITCH])) * (GU_PI / 180.0f)); sceGumRotateX ((e->angles1[ROLL] + ( blend * d[ROLL])) * (GU_PI / 180.0f)); } sceGumUpdateMatrix(); } /* ============================================================= SPRITE MODELS ============================================================= */ extern vec3_t lightcolor; // LordHavoc: .lit support /* ================ R_GetSpriteFrame ================ */ mspriteframe_t *R_GetSpriteFrame (entity_t *currententity) { msprite_t *psprite; mspritegroup_t *pspritegroup; mspriteframe_t *pspriteframe; int i, numframes, frame; float *pintervals, fullinterval, targettime, time; psprite = static_cast(currententity->model->cache.data); frame = currententity->frame; if ((frame >= psprite->numframes) || (frame < 0)) { Con_Printf ("R_DrawSprite: no such frame %d\n", frame); frame = 0; } if (psprite->frames[frame].type == SPR_SINGLE) { pspriteframe = psprite->frames[frame].frameptr; } else { pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; pintervals = pspritegroup->intervals; numframes = pspritegroup->numframes; fullinterval = pintervals[numframes-1]; time = cl.time + currententity->syncbase; // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values // are positive, so we don't have to worry about division by 0 targettime = time - ((int)(time / fullinterval)) * fullinterval; for (i=0 ; i<(numframes-1) ; i++) { if (pintervals[i] > targettime) break; } pspriteframe = pspritegroup->frames[i]; } return pspriteframe; } /* ================= R_DrawSpriteModel ================= */ void R_DrawSpriteModel (entity_t *e) { vec3_t point, v_forward, v_right, v_up; msprite_t *psprite; mspriteframe_t *frame; float *s_up, *s_right; float angle, sr, cr; float scale = ENTSCALE_DECODE(e->scale); if (scale == 0) scale = 1.0f; bool additive = false; bool filter = false; // don't even bother culling, because it's just a single polygon without a surface cache frame = R_GetSpriteFrame (e); psprite = static_cast(currententity->model->cache.data); switch(psprite->type) { case SPR_VP_PARALLEL_UPRIGHT: //faces view plane, up is towards the heavens v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = vright; break; case SPR_FACING_UPRIGHT: //faces camera origin, up is towards the heavens VectorSubtract(currententity->origin, r_origin, v_forward); v_forward[2] = 0; VectorNormalizeFast(v_forward); v_right[0] = v_forward[1]; v_right[1] = -v_forward[0]; v_right[2] = 0; v_up[0] = 0; v_up[1] = 0; v_up[2] = 1; s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL: //faces view plane, up is towards the top of the screen s_up = vup; s_right = vright; break; case SPR_ORIENTED: //pitch yaw roll are independent of camera AngleVectors (currententity->angles, v_forward, v_right, v_up); s_up = v_up; s_right = v_right; break; case SPR_VP_PARALLEL_ORIENTED: //faces view plane, but obeys roll value angle = DEG2RAD(currententity->angles[ROLL]); #ifdef PSP_VFPU sr = vfpu_sinf(angle); cr = vfpu_cosf(angle); #else sr = sin(angle); cr = cos(angle); #endif v_right[0] = vright[0] * cr + vup[0] * sr; v_up[0] = vright[0] * -sr + vup[0] * cr; v_right[1] = vright[1] * cr + vup[1] * sr; v_up[1] = vright[1] * -sr + vup[1] * cr; v_right[2] = vright[2] * cr + vup[2] * sr; v_up[2] = vright[2] * -sr + vup[2] * cr; s_up = v_up; s_right = v_right; break; default: return; } if (psprite->beamlength == 10) // we use the beam length of sprites, since they are unused by quake anyway. additive = true; if (psprite->beamlength == 20) filter = true; // Bind the texture. GL_Bind(frame->gl_texturenum); sceGuEnable(GU_BLEND); sceGuDepthMask(GU_TRUE); Fog_DisableGFog (); if (additive) { sceGuDepthMask(GU_TRUE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0xFFFFFFFF); sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGB); } else if (filter) { sceGuDepthMask(GU_TRUE); sceGuBlendFunc(GU_ADD, GU_FIX, GU_SRC_COLOR, 0, 0); sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGB); } else sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); // Allocate memory for this polygon. glvert_t* const vertices = static_cast(sceGuGetMemory(sizeof(glvert_t) * 4)); VectorMA (e->origin, frame->down * scale, s_up, point); VectorMA (point, frame->left * scale, s_right, point); vertices[0].st[0] = 0.0f; vertices[0].st[1] = 1.0f; vertices[0].xyz[0] = point[0]; vertices[0].xyz[1] = point[1]; vertices[0].xyz[2] = point[2]; VectorMA (e->origin, frame->up * scale, s_up, point); VectorMA (point, frame->left * scale, s_right, point); vertices[1].st[0] = 0.0f; vertices[1].st[1] = 0.0f; vertices[1].xyz[0] = point[0]; vertices[1].xyz[1] = point[1]; vertices[1].xyz[2] = point[2]; VectorMA (e->origin, frame->up * scale, s_up, point); VectorMA (point, frame->right * scale, s_right, point); vertices[2].st[0] = 1.0f; vertices[2].st[1] = 0.0f; vertices[2].xyz[0] = point[0]; vertices[2].xyz[1] = point[1]; vertices[2].xyz[2] = point[2]; VectorMA (e->origin, frame->down * scale, s_up, point); VectorMA (point, frame->right * scale, s_right, point); vertices[3].st[0] = 1.0f; vertices[3].st[1] = 1.0f; vertices[3].xyz[0] = point[0]; vertices[3].xyz[1] = point[1]; vertices[3].xyz[2] = point[2]; // Draw the clipped vertices. sceGuDrawArray( GU_TRIANGLE_FAN,GU_TEXTURE_32BITF | GU_VERTEX_32BITF,4, 0, vertices); sceGuDepthMask(GU_FALSE); sceGuDisable(GU_BLEND); Fog_EnableGFog (); sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); } /* ============================================================= ALIAS MODELS ============================================================= */ #define NUMVERTEXNORMALS 162 #define INTERP_WEAP_MAXNUM 24 #define INTERP_WEAP_MINDIST 5000 #define INTERP_WEAP_MAXDIST 95000 #define INTERP_MINDIST 70 #define INTERP_MAXDIST 300 extern "C" float r_avertexnormals[NUMVERTEXNORMALS][3]; float r_avertexnormals[NUMVERTEXNORMALS][3] = { #include "../../anorms.h" }; vec3_t shadevector; float shadelight, ambientlight; // precalculated dot products for quantized angles #define SHADEDOT_QUANT 16 float r_avertexnormal_dots[SHADEDOT_QUANT][256] = #include "../../anorm_dots.h" ; float *shadedots = r_avertexnormal_dots[0]; // fenix@io.com: model animation interpolation int lastposenum0; // int lastposenum; // fenix@io.com: model transform interpolation float old_i_model_transform; // // void GL_DrawAliasBlendedWireFrame (aliashdr_t *paliashdr, int pose1, int pose2, float blend) // { // trivertx_t* verts1; // trivertx_t* verts2; // int* order; // int count; // vec3_t d; // vec3_t point; // lastposenum0 = pose1; // lastposenum = pose2; // verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); // verts2 = verts1; // verts1 += pose1 * paliashdr->poseverts; // verts2 += pose2 * paliashdr->poseverts; // order = (int *)((byte *)paliashdr + paliashdr->commands); // int numcommands = order[0]; // order++; // struct vertex // { // int uvs; // char x, y, z; // char _padding; // }; // sceGuColor(GU_COLOR(lightcolor[0], lightcolor[1], lightcolor[2], 1.0f)); // // Allocate the vertices. // vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * numcommands)); // int vertex_index = 0; // //for blubs's alternate BuildTris: 1) Disable while(1) loop 2) Disable the break; 3) replace GU_TRIANGLE_STRIP with GU_TRIANGLES // while (1) // { // // get the vertex count and primitive type // count = *order++; // if (!count) break; // if (count < 0) // count = -count; // for (int start = vertex_index; vertex_index < (start + count); ++vertex_index) // { // // texture coordinates come from the draw list // out[vertex_index].uvs = order[0]; // order += 1; // VectorSubtract(verts2->v, verts1->v, d); // // blend the vertex positions from each frame together // point[0] = verts1->v[0] + (blend * d[0]); // point[1] = verts1->v[1] + (blend * d[1]); // point[2] = verts1->v[2] + (blend * d[2]); // out[vertex_index].x = point[0]; // out[vertex_index].y = point[1]; // out[vertex_index].z = point[2]; // ++verts1; // ++verts2; // } // sceGuDrawArray(GU_LINE_STRIP, GU_TEXTURE_16BIT | GU_VERTEX_8BIT, count, 0, &out[vertex_index - count]); // } // sceGuEnable(GU_TEXTURE_2D); // sceGuColor(0xffffffff); // } /* ============= GL_DrawAliasFrame ============= */ void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum) { // if (r_showtris.value) // { // GL_DrawAliasBlendedWireFrame(paliashdr, posenum, posenum, 0); // return; // } trivertx_t *verts; int *order; int count; int prim; lastposenum = posenum; verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); verts += posenum * paliashdr->poseverts; order = (int *)((byte *)paliashdr + paliashdr->commands); int numcommands = order[0]; order++; qboolean isStatic = paliashdr->numposes <= 1 ? qtrue : qfalse; struct vertex { int uvs; int xyz; }; sceGuColor(GU_COLOR(lightcolor[0], lightcolor[1], lightcolor[2], 1.0f)); if (isStatic) { while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { prim = GU_TRIANGLE_FAN; count = -count; } else { prim = GU_TRIANGLE_STRIP; } sceGuDrawArray(prim, GU_TEXTURE_16BIT | GU_VERTEX_8BIT, count, 0, order); order += 2 * count; } } else { // Allocate the vertices. vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * numcommands)); int vertex_index = 0; //for blubs's alternate BuildTris: 1) Disable while(1) loop 2) Disable the break; 3) replace GU_TRIANGLE_STRIP with GU_TRIANGLES while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done if (count < 0) { prim = GU_TRIANGLE_FAN; count = -count; } else { prim = GU_TRIANGLE_STRIP; //prim = GU_TRIANGLES; //used for blubs' alternate BuildTris with one continual triangle list } //================================================================== fps: 50 =============================================== for (int start = vertex_index; vertex_index < (start + count); ++vertex_index, ++order, ++verts) { // texture coordinates come from the draw list out[vertex_index].uvs = order[0]; out[vertex_index].xyz = ((int*)verts->v)[0]; // cast to int because trivertx is is 4 bytes } sceGuDrawArray(prim, GU_TEXTURE_16BIT | GU_VERTEX_8BIT, count, 0, &out[vertex_index - count]); //================================================================== fps: 50 =============================================== } } sceGuColor(0xffffffff); } /* ============= GL_DrawAliasBlendedFrame fenix@io.com: model animation interpolation ============= */ void GL_DrawAliasBlendedFrame (aliashdr_t *paliashdr, int pose1, int pose2, float blend) { // if (r_showtris.value) // { // GL_DrawAliasBlendedWireFrame(paliashdr, pose1, pose2, blend); // return; // } trivertx_t* verts1; trivertx_t* verts2; int* order; int count; vec3_t d; vec3_t point; int prim; prim = GU_TRIANGLE_FAN; lastposenum0 = pose1; lastposenum = pose2; verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); verts2 = verts1; verts1 += pose1 * paliashdr->poseverts; verts2 += pose2 * paliashdr->poseverts; order = (int *)((byte *)paliashdr + paliashdr->commands); int numcommands = order[0]; order++; struct vertex { int uvs; int xyz; }; sceGuColor(GU_COLOR(lightcolor[0], lightcolor[1], lightcolor[2], 1.0f)); // Allocate the vertices. vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * numcommands * 2)); int vertex_index = 0; //for blubs's alternate BuildTris: 1) Disable while(1) loop 2) Disable the break; 3) replace GU_TRIANGLE_STRIP with GU_TRIANGLES while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; if (count < 0) { prim = GU_TRIANGLE_FAN; count = -count; } else { prim = GU_TRIANGLE_STRIP; //prim = GU_TRIANGLES; //used for blubs' alternate BuildTris with one continual triangle list } for (int start = vertex_index; vertex_index < (start + count * 2); ++vertex_index, ++order, ++verts1, ++verts2) { out[vertex_index].uvs = order[0]; out[vertex_index].xyz = ((int*)verts1->v)[0]; ++vertex_index; out[vertex_index].uvs = order[0]; out[vertex_index].xyz = ((int*)verts2->v)[0]; } sceGuMorphWeight(0, 1 - blend); sceGuMorphWeight(1, blend); sceGuDrawArray(prim, GU_TEXTURE_16BIT | GU_VERTEX_8BIT | GU_VERTICES(2), count, 0, &out[vertex_index - count * 2]); } sceGuColor(0xffffffff); } /* ================= R_SetupAliasFrame ================= */ void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr) { int pose, numposes; float interval; if ((frame >= paliashdr->numframes) || (frame < 0)) { Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); frame = 0; } pose = paliashdr->frames[frame].firstpose; numposes = paliashdr->frames[frame].numposes; if (numposes > 1) { interval = paliashdr->frames[frame].interval; pose += (int)(cl.time / interval) % numposes; } GL_DrawAliasFrame (paliashdr, pose); } /* ================= R_SetupAliasBlendedFrame fenix@io.com: model animation interpolation ================= */ //double t1, t2, t3; void R_SetupAliasBlendedFrame (int frame, aliashdr_t *paliashdr, entity_t* e) { int pose; int numposes; float blend; if ((frame >= paliashdr->numframes) || (frame < 0)) { Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); frame = 0; } // HACK: if we're a certain distance away, don't bother blending // cypress -- Lets not care about Z (up).. chances are they're out of the frustum anyway int dist_x = (cl.viewent.origin[0] - e->origin[0]); int dist_y = (cl.viewent.origin[1] - e->origin[1]); int distance_from_client = (int)((dist_x) * (dist_x) + (dist_y) * (dist_y)); // no use sqrting, just slows us down. // They're too far away from us to care about blending their frames. if (distance_from_client >= 160000) { // 400 * 400 // Fix them from jumping from last lerp e->pose1 = e->pose2 = paliashdr->frames[frame].firstpose; e->frame_interval = 0.1; GL_DrawAliasFrame (paliashdr, paliashdr->frames[frame].firstpose); } else { pose = paliashdr->frames[frame].firstpose; numposes = paliashdr->frames[frame].numposes; if (numposes > 1) { e->frame_interval = paliashdr->frames[frame].interval; pose += (int)(cl.time / e->frame_interval) % numposes; } else { /* One tenth of a second is a good for most Quake animations. If the nextthink is longer then the animation is usually meant to pause (e.g. check out the shambler magic animation in shambler.qc). If its shorter then things will still be smoothed partly, and the jumps will be less noticable because of the shorter time. So, this is probably a good assumption. */ e->frame_interval = 0.1; } if (e->pose2 != pose) { e->frame_start_time = realtime; e->pose1 = e->pose2; e->pose2 = pose; blend = 0; } else blend = (realtime - e->frame_start_time) / e->frame_interval; // wierd things start happening if blend passes 1 if (cl.paused || blend > 1) blend = 1; if (blend == 1) GL_DrawAliasFrame (paliashdr, pose); else GL_DrawAliasBlendedFrame (paliashdr, e->pose1, e->pose2, blend); } } /* ============= GL_DrawQ2AliasFrame ============= */ void GL_DrawQ2AliasFrame (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp) { float ilerp, l; int *order, count; md2trivertx_t *verts1, *verts2; vec3_t scale1, translate1, scale2, translate2; md2frame_t *frame1, *frame2; sceGuShadeModel(GU_SMOOTH); ilerp = 1.0f - lerp; //new version by muff - fixes bug, easier to read, faster (well slightly) frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose)); frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose)); VectorCopy(frame1->scale, scale1); VectorCopy(frame1->translate, translate1); VectorCopy(frame2->scale, scale2); VectorCopy(frame2->translate, translate2); verts1 = &frame1->verts[0]; verts2 = &frame2->verts[0]; order = (int *)((int)pheader + pheader->ofs_glcmds); while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done int prim; if (count < 0) { count = -count; prim = GU_TRIANGLE_FAN; } else { prim = GU_TRIANGLE_STRIP; } // Allocate the vertices. struct vertex { float u, v; unsigned int color; float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * count)); for (int vertex_index = 0; vertex_index < count; ++vertex_index) { // texture coordinates come from the draw list out[vertex_index].u = ((float *)order)[0]; out[vertex_index].v = ((float *)order)[1]; l = shadedots[verts1->lightnormalindex]; //l = shadedots[verts2->lightnormalindex] - shadedots[verts1->lightnormalindex]; float r,g,b; r = l * lightcolor[0]; g = l * lightcolor[1]; b = l * lightcolor[2]; if(r > 1) r = 1; if(g > 1) g = 1; if(b > 1) b = 1; out[vertex_index].x = (verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+ (verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp; out[vertex_index].y = (verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+ (verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp; out[vertex_index].z = (verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+ (verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp; out[vertex_index].color = GU_COLOR(r, g, b, 1.0f); order+=3; } if(r_showtris.value) { sceGuDisable(GU_TEXTURE_2D); } sceGuDrawArray(r_showtris.value ? GU_LINE_STRIP : prim, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_COLOR_8888, count, 0, out); if(r_showtris.value) { sceGuEnable(GU_TEXTURE_2D); } } sceGuColor(0xffffffff); } /* ============= GL_DrawQ2AliasShadow ============= */ extern vec3_t lightspot; void GL_DrawQ2AliasShadow (entity_t *e, md2_t *pheader, int lastpose, int pose, float lerp) { float ilerp, height, lheight; int *order, count; md2trivertx_t *verts1, *verts2; vec3_t scale1, translate1, scale2, translate2, point; md2frame_t *frame1, *frame2; // Tomaz - New Shadow Begin trace_t downtrace; vec3_t downmove; float s1,c1; // Tomaz - New Shadow End lheight = currententity->origin[2] - lightspot[2]; height = 0; ilerp = 1.0 - lerp; // Tomaz - New Shadow Begin VectorCopy (e->origin, downmove); downmove[2] = downmove[2] - 4096; memset (&downtrace, 0, sizeof(downtrace)); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, e->origin, downmove, &downtrace); #ifdef PSP_VFPU s1 = vfpu_sinf( e->angles[1]/180*M_PI); c1 = vfpu_cosf( e->angles[1]/180*M_PI); #else s1 = sin( e->angles[1]/180*M_PI); c1 = cos( e->angles[1]/180*M_PI); #endif // Tomaz - New Shadow End //new version by muff - fixes bug, easier to read, faster (well slightly) frame1 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * lastpose)); frame2 = (md2frame_t *)((int) pheader + pheader->ofs_frames + (pheader->framesize * pose)); VectorCopy(frame1->scale, scale1); VectorCopy(frame1->translate, translate1); VectorCopy(frame2->scale, scale2); VectorCopy(frame2->translate, translate2); verts1 = &frame1->verts[0]; verts2 = &frame2->verts[0]; order = (int *)((int) pheader + pheader->ofs_glcmds); height = -lheight + 1.0; while (1) { // get the vertex count and primitive type count = *order++; if (!count) break; // done int prim; if (count < 0) { count = -count; prim = GU_TRIANGLE_FAN; } else { prim = GU_TRIANGLE_STRIP; } // Allocate the vertices. struct vertex { float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * count)); for (int vertex_index = 0; vertex_index < count; ++vertex_index) { point[0] = (verts1[order[2]].v[0]*scale1[0]+translate1[0])*ilerp+(verts2[order[2]].v[0]*scale2[0]+translate2[0])*lerp; point[1] = (verts1[order[2]].v[1]*scale1[1]+translate1[1])*ilerp+(verts2[order[2]].v[1]*scale2[1]+translate2[1])*lerp; point[2] = (verts1[order[2]].v[2]*scale1[2]+translate1[2])*ilerp+(verts2[order[2]].v[2]*scale2[2]+translate2[2])*lerp; // Tomaz - New shadow Begin point[2] = - (e->origin[2] - downtrace.endpos[2]) ; point[2] += ((point[1] * (s1 * downtrace.plane.normal[0])) - (point[0] * (c1 * downtrace.plane.normal[0])) - (point[0] * (s1 * downtrace.plane.normal[1])) - (point[1] * (c1 * downtrace.plane.normal[1]))) + ((1.0 - downtrace.plane.normal[2])*20) + 0.2 ; out[vertex_index].x = point[0]; out[vertex_index].y = point[1]; out[vertex_index].z = point[2]; // Tomaz - New shadow Begin order+=3; } if(r_showtris.value) { sceGuDisable(GU_TEXTURE_2D); } sceGuDrawArray(r_showtris.value ? GU_LINE_STRIP : prim,GU_VERTEX_32BITF, count, 0, out); if(r_showtris.value) { sceGuEnable(GU_TEXTURE_2D); } } } /* ================= R_SetupQ2AliasFrame ================= */ void R_SetupQ2AliasFrame (entity_t *e, md2_t *pheader) { int frame; float lerp; frame = e->frame; sceGumPushMatrix (); R_RotateForEntity (e, 0, e->scale); if ((frame >= pheader->num_frames) || (frame < 0)) { Con_DPrintf ("R_SetupQ2AliasFrame: no such frame %d\n", frame); frame = 0; } if (e->draw_lastmodel == e->model) { if (frame != e->draw_pose) { e->draw_lastpose = e->draw_pose; e->draw_pose = frame; e->draw_lerpstart = cl.time; lerp = 0; } else lerp = (cl.time - e->draw_lerpstart) * 10.0; } else // uninitialized { e->draw_lastmodel = e->model; e->draw_lastpose = e->draw_pose = frame; e->draw_lerpstart = cl.time; lerp = 0; } if (lerp > 1) lerp = 1; GL_DrawQ2AliasFrame (e, pheader, e->draw_lastpose, frame, lerp); if (r_shadows.value) { trace_t downtrace; vec3_t downmove; VectorCopy (e->origin, downmove); downmove[2] = downmove[2] - 4096; memset (&downtrace, 0, sizeof(downtrace)); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, e->origin, downmove, &downtrace); sceGuDisable (GU_TEXTURE_2D); sceGuEnable (GU_BLEND); sceGuDepthMask(GU_TRUE); // disable zbuffer updates sceGuColor(GU_COLOR(0,0,0,(1 - ((e->origin[2] + e->model->mins[2]-downtrace.endpos[2])/60)))); //stencil shadows sceGuEnable(GU_STENCIL_TEST); sceGuStencilFunc(GU_EQUAL,1,2); sceGuStencilOp(GU_KEEP,GU_KEEP,GU_INCR); GL_DrawQ2AliasShadow (e, pheader, e->draw_lastpose, frame, lerp); sceGuDisable(GU_STENCIL_TEST); sceGuDepthMask(GU_FALSE); // enable zbuffer updates sceGuEnable (GU_TEXTURE_2D); sceGuDisable (GU_BLEND); sceGuColor(0xffffffff); } sceGumPopMatrix(); sceGumUpdateMatrix(); } void IgnoreInterpolatioFrame (entity_t *e, aliashdr_t *paliashdr) { if (strcmp(e->old_model, e->model->name) && e->model != NULL) { strcpy(e->old_model, e->model->name); // fenix@io.com: model transform interpolation e->frame_start_time = 0; e->translate_start_time = 0; e->rotate_start_time = 0; e->pose1 = 0; e->pose2 = paliashdr->frames[e->frame].firstpose; } } /* ===================== R_DrawZombieLimb ===================== */ //Blubs Z hacks: need this declaration. model_t *Mod_FindName (char *name); void R_DrawZombieLimb (entity_t *e,int which) { //entity_t *e; model_t *clmodel; aliashdr_t *paliashdr; entity_t *limb_ent; //e = &cl_entities[ent]; //clmodel = e->model; if(which == 1) limb_ent = &cl_entities[e->z_head]; else if(which == 2) limb_ent = &cl_entities[e->z_larm]; else if(which == 3) limb_ent = &cl_entities[e->z_rarm]; else return; clmodel = limb_ent->model; if(clmodel == NULL) return; VectorCopy (e->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // locate the proper data paliashdr = (aliashdr_t *)Mod_Extradata (clmodel);//e->model c_alias_polys += paliashdr->numtris; sceGumPushMatrix(); //movement interpolation by blubs R_InterpolateEntity(e,0); //blubs disabled /*if (r_i_model_transform.value) R_BlendedRotateForEntity (e, 0); else R_RotateForEntity (e, 0);*/ const ScePspFVector3 translation = { paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] }; sceGumTranslate(&translation); const ScePspFVector3 scaling = { paliashdr->scale[0] * 128.f, paliashdr->scale[1] * 128.f, paliashdr->scale[2] * 128.f }; sceGumScale(&scaling); sceGumUpdateMatrix(); IgnoreInterpolatioFrame(e, paliashdr); // Make sure we never try to do blended frame on models with just single frame if (r_i_model_animation.value && paliashdr->numposes > 1) { R_SetupAliasBlendedFrame (e->frame, paliashdr, e); } else { R_SetupAliasFrame (e->frame, paliashdr); } //t3 += Sys_FloatTime(); sceGumPopMatrix(); sceGumUpdateMatrix(); } /* ================= R_DrawTransparentAliasModel blubs: used for semitransparent fullbright models (like their sprite counterparts) ================= */ void R_DrawTransparentAliasModel (entity_t *e) { model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; float an; int anim; clmodel = e->model; VectorAdd (e->origin, clmodel->mins, mins); VectorAdd (e->origin, clmodel->maxs, maxs); if (R_CullBox(mins, maxs) == 2) return; VectorCopy (e->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // LordHavoc: .lit support begin //ambientlight = shadelight = R_LightPoint (e->origin); // LordHavoc: original code, removed shadelight and ambientlight R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this // LordHavoc: .lit support end lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; // LordHavoc: .lit support begin //shadelight = shadelight / 200.0; // LordHavoc: original code VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); // LordHavoc: .lit support end an = e->angles[1]/180*M_PI; shadevector[0] = cosf(-an); shadevector[1] = sinf(-an); shadevector[2] = 1; VectorNormalize (shadevector); // locate the proper data// paliashdr = (aliashdr_t *)Mod_Extradata (e->model); c_alias_polys += paliashdr->numtris; // draw all the triangles// sceGumPushMatrix(); R_InterpolateEntity(e,0); const ScePspFVector3 translation = { paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] }; sceGumTranslate(&translation); const ScePspFVector3 scaling = { paliashdr->scale[0] * 128.f, paliashdr->scale[1] * 128.f, paliashdr->scale[2] * 128.f }; sceGumScale(&scaling); //for models(pink transparency) sceGuEnable(GU_BLEND); sceGuEnable(GU_ALPHA_TEST); sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); //st1x:now quake transparency is working //force_fullbright //sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuShadeModel(GU_SMOOTH); sceGumUpdateMatrix(); IgnoreInterpolatioFrame(e, paliashdr); anim = (int)(cl.time*10) & 3; GL_Bind(paliashdr->gl_texturenum[e->skinnum][anim]); //Rendering block if (r_i_model_animation.value) { R_SetupAliasBlendedFrame (e->frame, paliashdr, e); } else { R_SetupAliasFrame (e->frame, paliashdr); } sceGumPopMatrix(); sceGumUpdateMatrix(); //st1x:now quake transparency is working sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA); sceGuShadeModel(GU_FLAT); // else if(ISGLOW(e)) { sceGuDepthMask(GU_FALSE); //sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //sceGuDisable (GU_BLEND); } sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDisable(GU_BLEND); } /* ================= R_DrawAliasModel ================= */ int doZHack; void R_DrawAliasModel (entity_t *e) { char specChar; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; float an; int anim; bool force_fullbright, additive; clmodel = e->model; VectorAdd (e->origin, clmodel->mins, mins); VectorAdd (e->origin, clmodel->maxs, maxs); if (R_CullBox(mins, maxs) == 2) return; //=============================================================================================== 97% at this point if(ISADDITIVE(e)) { float deg = e->renderamt; float alpha_val = deg; float alpha_val2 = 1 - deg; if(deg <= 0.7) sceGuDepthMask(GU_TRUE); sceGuEnable (GU_BLEND); sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, GU_COLOR(alpha_val,alpha_val,alpha_val,alpha_val), GU_COLOR(alpha_val2,alpha_val2,alpha_val2,alpha_val2)); } else if(ISGLOW(e)) { sceGuDepthMask(GU_TRUE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0xFFFFFFFF); sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); } else if (ISSOLID(e)) { sceGuEnable(GU_ALPHA_TEST); float c = (e->renderamt) * 255.0f; sceGuAlphaFunc(GU_GREATER, 0x88, c); } force_fullbright = false; additive = false; VectorCopy (e->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // // LordHavoc: .lit support begin //ambientlight = shadelight = R_LightPoint (e->origin); // LordHavoc: original code, removed shadelight and ambientlight R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this // LordHavoc: .lit support end //blubswillrule: disabled dynamic lights /*for (lnum=0 ; lnum= cl.time) { VectorSubtract (e->origin,cl_dlights[lnum].origin,dist); add = cl_dlights[lnum].radius - Length(dist); if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].color[0]; lightcolor[1] += add * cl_dlights[lnum].color[1]; lightcolor[2] += add * cl_dlights[lnum].color[2]; } // LordHavoc: .lit support end } }*/ //Shpuld if(r_model_brightness.value) { lightcolor[0] += 32; lightcolor[1] += 32; lightcolor[2] += 32; } for(int g = 0; g < 3; g++) { if(lightcolor[g] < 8) lightcolor[g] = 8; if(lightcolor[g] > 125) lightcolor[g] = 125; } specChar = clmodel->name[strlen(clmodel->name) - 5]; if(specChar == '!' || e->effects & EF_FULLBRIGHT) { lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; force_fullbright = true; } if(specChar == '@') { alphafunc = true; } if(specChar == '&') { lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; force_fullbright = true; alphafunc = true; } //t3 += Sys_FloatTime(); shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; // LordHavoc: .lit support begin //shadelight = shadelight / 200.0; // LordHavoc: original code VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); // LordHavoc: .lit support end an = e->angles[1]/180*M_PI; shadevector[0] = cosf(-an); shadevector[1] = sinf(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // if(doZHack && specChar == '%') { if(clmodel->name[12] == 'c') paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zcfull.mdl")); else paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zfull.mdl")); } else paliashdr = (aliashdr_t *)Mod_Extradata (e->model); c_alias_polys += paliashdr->numtris; // // draw all the triangles // sceGumPushMatrix(); R_InterpolateEntity(e,0); // Special handling of view model to keep FOV from altering look. Pretty good. Not perfect but rather close. if ((e == &cl.viewent || e == &cl.viewent2) && scr_fov_viewmodel.value) { float scale = 1.0f / tan (DEG2RAD (scr_fov.value / 2.0f)) * scr_fov_viewmodel.value / 90.0f; if (e->scale != ENTSCALE_DEFAULT && e->scale != 0) scale *= ENTSCALE_DECODE(e->scale); const ScePspFVector3 translation = { paliashdr->scale_origin[0] * scale, paliashdr->scale_origin[1], paliashdr->scale_origin[2] }; const ScePspFVector3 scaling = { paliashdr->scale[0] * scale * 128.f, paliashdr->scale[1] * 128.f, paliashdr->scale[2] * 128.f }; sceGumTranslate(&translation); sceGumScale(&scaling); } else { float scale = 1.0f; if (e->scale != ENTSCALE_DEFAULT && e->scale != 0) scale *= ENTSCALE_DECODE(e->scale); const ScePspFVector3 translation = { paliashdr->scale_origin[0] * scale, paliashdr->scale_origin[1] * scale, paliashdr->scale_origin[2] * scale }; const ScePspFVector3 scaling = { paliashdr->scale[0] * (scale * 128.0f), paliashdr->scale[1] * (scale * 128.0f), paliashdr->scale[2] * (scale * 128.0f) }; sceGumTranslate(&translation); sceGumScale(&scaling); } //============================================================================================================================= 83% at this point // we can't dynamically colormap textures, so they are cached // seperately for the players. Heads are just uncolored. //if (e->colormap != vid.colormap && 0 /* && !gl_nocolors.value*/) //{ // i = e - cl_entities; // if (i >= 1 && i<=cl.maxclients /*&& !strcmp (e->model->name, "models/player.mdl")*/) // { // GL_Bind(playertextures - 1 + i); // } //} //for models(pink transparency) if (alphafunc) { sceGuEnable(GU_ALPHA_TEST); sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); } //st1x:now quake transparency is working if (force_fullbright) sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); else sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); //for models (blue transparency) if (alphafunc2 || alphafunc) { sceGuEnable(GU_ALPHA_TEST); sceGuAlphaFunc(GU_GREATER, 0xaa, 0xff); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); } sceGuShadeModel(GU_SMOOTH); sceGumUpdateMatrix(); IgnoreInterpolatioFrame(e, paliashdr); anim = (int)(cl.time*10) & 3; GL_Bind(paliashdr->gl_texturenum[e->skinnum][anim]); //===================================================================================================== 80% at this point //Rendering block if (r_i_model_animation.value) { R_SetupAliasBlendedFrame (e->frame, paliashdr, e); } else { R_SetupAliasFrame (e->frame, paliashdr); } sceGumPopMatrix(); sceGumUpdateMatrix(); if (doZHack == 0 && specChar == '%')//if we're drawing zombie, also draw its limbs in one call { if(e->z_head) R_DrawZombieLimb(e,1); if(e->z_larm) R_DrawZombieLimb(e,2); if(e->z_rarm) R_DrawZombieLimb(e,3); } //st1x:now quake transparency is working sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA); sceGuShadeModel(GU_FLAT); //Blubswillrule: disabled the next two calls, they look like duplicates //sceGuShadeModel(GU_FLAT); //sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); if (ISADDITIVE(e)) { float deg = e->renderamt; if(deg <= 0.7) sceGuDepthMask(GU_FALSE); //sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //sceGuDisable (GU_BLEND); } else if(ISSOLID(e)) { sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); } else if(ISGLOW(e)) { sceGuDepthMask(GU_FALSE); //sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //sceGuDisable (GU_BLEND); } sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDisable(GU_BLEND); } void R_DrawMD2Model (entity_t *e) { int i; int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; float an; bool force_fullbright, additive; md2_t *pheader; // LH / muff if(ISADDITIVE(e)) { float deg = e->renderamt; float alpha_val = deg; float alpha_val2 = 1 - deg; if(deg <= 0.7) sceGuDepthMask(GU_TRUE); sceGuEnable (GU_BLEND); sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, GU_COLOR(alpha_val,alpha_val,alpha_val,alpha_val), GU_COLOR(alpha_val2,alpha_val2,alpha_val2,alpha_val2)); } else if(ISGLOW(e)) { sceGuDepthMask(GU_TRUE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0xFFFFFFFF); sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGBA); } else if (ISSOLID(e)) { sceGuEnable(GU_ALPHA_TEST); float c = (e->renderamt) * 255.0f; sceGuAlphaFunc(GU_GREATER, 0x88, c); } force_fullbright = false; additive = false; clmodel = e->model; VectorAdd (e->origin, clmodel->mins, mins); VectorAdd (e->origin, clmodel->maxs, maxs); //if (e->angles[0] || e->angles[1] || e->angles[2]) //{ // if (R_CullSphere(e->origin, clmodel->radius)) // return; //} //else //{ if (R_CullBox(mins, maxs) == 2) return; //} VectorCopy (e->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // // LordHavoc: .lit support begin //ambientlight = shadelight = R_LightPoint (e->origin); // LordHavoc: original code, removed shadelight and ambientlight R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this // LordHavoc: .lit support end // always give the gun some light // LordHavoc: .lit support begin //if (e == &cl.viewent && ambientlight < 24) // LordHavoc: original code // ambientlight = shadelight = 24; // LordHavoc: original code /* if (e == &cl.viewent) { if (lightcolor[0] < 24) lightcolor[0] = 24; if (lightcolor[1] < 24) lightcolor[1] = 24; if (lightcolor[2] < 24) lightcolor[2] = 24; } */ // LordHavoc: .lit support end for (lnum=0 ; lnum= cl.time) { VectorSubtract (e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - Length(dist); // LordHavoc: .lit support begin /* LordHavoc: original code if (add > 0) { ambientlight += add; //ZOID models should be affected by dlights as well shadelight += add; } */ if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].color[0]; lightcolor[1] += add * cl_dlights[lnum].color[1]; lightcolor[2] += add * cl_dlights[lnum].color[2]; } // LordHavoc: .lit support end } } // clamp lighting so it doesn't overbright as much /* if (shadelight > 65) shadelight = 65; if (ambientlight > 196) { ambientlight = 196; force_fullbright = true; } else force_fullbright = false; */ // ZOID: never allow players to go totally black // i = e - cl_entities; // if (i >= 1 && i<=cl.maxclients /*&& !strcmp (e->model->name, "models/player.mdl") */) // LordHavoc: .lit support begin // if (ambientlight < 8) // LordHavoc: original code // ambientlight = shadelight = 8; // LordHavoc: original code //Shpuld if(r_model_brightness.value) { lightcolor[0] += 32; lightcolor[1] += 32; lightcolor[2] += 32; } for(int g = 0; g < 3; g++) { if(lightcolor[g] < 8) lightcolor[g] = 8; if(lightcolor[g] > 125) lightcolor[g] = 125; } // HACK HACK HACK -- no fullbright colors, so make torches and projectiles full light if (!strcmp (clmodel->name, "progs/flame2.mdl") || !strcmp (clmodel->name, "progs/flame.mdl") || !strcmp (clmodel->name, "progs/lavaball.mdl") || !strcmp (clmodel->name, "progs/bolt.mdl") || !strcmp (clmodel->name, "models/misc/bolt2.mdl") || !strcmp (clmodel->name, "progs/bolt3.mdl") || !strcmp (clmodel->name, "progs/eyes.mdl") || !strcmp (clmodel->name, "progs/k_spike.mdl") || !strcmp (clmodel->name, "progs/s_spike.mdl") || !strcmp (clmodel->name, "progs/spike.mdl") || !strcmp (clmodel->name, "progs/Misc/chalk.mdl") || !strcmp (clmodel->name, "progs/Misc/x2.mdl") || !strcmp (clmodel->name, "progs/Misc/nuke.mdl") || !strcmp (clmodel->name, "progs/Misc/instakill.mdl") || !strcmp (clmodel->name, "progs/Misc/perkbottle.mdl") || !strcmp (clmodel->name, "progs/Misc/carpenter.mdl") || !strcmp (clmodel->name, "progs/Misc/maxammo.mdl") || !strcmp (clmodel->name, "progs/Misc/lamp_ndu.mdl") || !strcmp (clmodel->name, "progs/laser.mdl")) { lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; force_fullbright = true; } if (e->effects & EF_FULLBRIGHT) { lightcolor[0] = lightcolor[1] = lightcolor[2] = 256; force_fullbright = true; } if (!strcmp (clmodel->name, "progs/v_rpg.mdl") || !strcmp (clmodel->name, "progs/stalker.mdl") || !strcmp (clmodel->name, "progs/VModels/scope.mdl")) { alphafunc = true; } shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; // LordHavoc: .lit support begin //shadelight = shadelight / 200.0; // LordHavoc: original code VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); // LordHavoc: .lit support end an = e->angles[1]/180*M_PI; shadevector[0] = cosf(-an); shadevector[1] = sinf(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // pheader = (md2_t *)Mod_Extradata (e->model); c_alias_polys += pheader->num_tris; // // draw all the triangles // GL_Bind(pheader->gl_texturenum[e->skinnum]); // we can't dynamically colormap textures, so they are cached // seperately for the players. Heads are just uncolored. if (e->colormap != vid.colormap && 0 /* && !gl_nocolors.value*/) { i = e - cl_entities; if (i >= 1 && i<=cl.maxclients /*&& !strcmp (e->model->name, "models/player.mdl")*/) { GL_Bind(playertextures - 1 + i); } } //for models(pink transparency) if (alphafunc) { sceGuEnable(GU_ALPHA_TEST); sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); } //st1x:now quake transparency is working if (force_fullbright) sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); else sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); //for models (blue transparency) if (alphafunc2) { sceGuEnable(GU_ALPHA_TEST); sceGuAlphaFunc(GU_GREATER, 0xaa, 0xff); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); } sceGuShadeModel(GU_SMOOTH); R_SetupQ2AliasFrame (e, pheader); //st1x:now quake transparency is working sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA); sceGuShadeModel(GU_FLAT); if (ISADDITIVE(e)) { float deg = e->renderamt; if(deg <= 0.7) sceGuDepthMask(GU_FALSE); //sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //sceGuDisable (GU_BLEND); } else if(ISSOLID(e)) { sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); } else if(ISGLOW(e)) { sceGuDepthMask(GU_FALSE); //sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); //sceGuDisable (GU_BLEND); } sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDisable(GU_BLEND); } //================================================================================== //=================================Q3 Models======================================== //================================================================================== int bodyframe = 0, legsframe = 0; animtype_t bodyanim, legsanim; //ScePspFMatrix4 matrix; void R_ReplaceQ3Frame (int frame) { animdata_t *currbodyanim, *currlegsanim; static animtype_t oldbodyanim, oldlegsanim; static float bodyanimtime, legsanimtime; static qboolean deathanim = qfalse; if (deathanim) { bodyanim = oldbodyanim; legsanim = oldlegsanim; } if (frame < 41 || frame > 102) deathanim = qfalse; if (frame >= 0 && frame <= 5) // axrun { bodyanim = torso_stand2; legsanim = legs_run; } else if (frame >= 6 && frame <= 11) // rockrun { bodyanim = torso_stand; legsanim = legs_run; } else if ((frame >= 12 && frame <= 16) || (frame >= 35 && frame <= 40)) // stand, pain { bodyanim = torso_stand; legsanim = legs_idle; } else if ((frame >= 17 && frame <= 28) || (frame >= 29 && frame <= 34)) // axstand, axpain { bodyanim = torso_stand2; legsanim = legs_idle; } else if (frame >= 41 && frame <= 102 && !deathanim) // axdeath, deatha, b, c, d, e { bodyanim = legsanim = both_death1; deathanim = qtrue; } else if (frame > 103 && frame <= 118) // gun attacks { bodyanim = torso_attack; } else if (frame >= 119) // axe attacks { bodyanim = torso_attack2; } currbodyanim = &anims[bodyanim]; currlegsanim = &anims[legsanim]; if (bodyanim == oldbodyanim) { if (cl.time >= bodyanimtime + currbodyanim->interval) { if (currbodyanim->loop_frames && bodyframe + 1 >= currbodyanim->offset + currbodyanim->loop_frames) bodyframe = currbodyanim->offset; else if (bodyframe + 1 < currbodyanim->offset + currbodyanim->num_frames) bodyframe++; bodyanimtime = cl.time; } } else { bodyframe = currbodyanim->offset; bodyanimtime = cl.time; } if (legsanim == oldlegsanim) { if (cl.time >= legsanimtime + currlegsanim->interval) { if (currlegsanim->loop_frames && legsframe + 1 >= currlegsanim->offset + currlegsanim->loop_frames) legsframe = currlegsanim->offset; else if (legsframe + 1 < currlegsanim->offset + currlegsanim->num_frames) legsframe++; legsanimtime = cl.time; } } else { legsframe = currlegsanim->offset; legsanimtime = cl.time; } oldbodyanim = bodyanim; oldlegsanim = legsanim; } int multimodel_level; bool surface_transparent; /* ================= R_DrawQ3Frame ================= */ void R_DrawQ3Frame (int frame, md3header_t *pmd3hdr, md3surface_t *pmd3surf, entity_t *ent, int distance) { int i, j, numtris, pose, pose1, pose2; float l, lerpfrac; vec3_t lightvec, interpolated_verts; unsigned int *tris; md3tc_t *tc; md3vert_mem_t *verts, *v1, *v2; model_t *clmodel = ent->model; if ((frame >= pmd3hdr->numframes) || (frame < 0)) { Con_DPrintf ("R_DrawQ3Frame: no such frame %d\n", frame); frame = 0; } if (ent->pose1 >= pmd3hdr->numframes) ent->pose1 = 0; pose = frame; if (!strcmp(clmodel->name, "models/player/lower.md3")) ent->frame_interval = anims[legsanim].interval; else if (!strcmp(clmodel->name, "models/player/upper.md3")) ent->frame_interval = anims[bodyanim].interval; else ent->frame_interval = 0.1; if (ent->pose2 != pose) { ent->frame_start_time = cl.time; ent->pose1 = ent->pose2; ent->pose2 = pose; ent->framelerp = 0; } else { ent->framelerp = (cl.time - ent->frame_start_time) / ent->frame_interval; } // weird things start happening if blend passes 1 if (cl.paused || ent->framelerp > 1) ent->framelerp = 1; verts = (md3vert_mem_t *)((byte *)pmd3hdr + pmd3surf->ofsverts); tc = (md3tc_t *)((byte *)pmd3surf + pmd3surf->ofstc); tris = (unsigned int *)((byte *)pmd3surf + pmd3surf->ofstris); numtris = pmd3surf->numtris * 3; pose1 = ent->pose1 * pmd3surf->numverts; pose2 = ent->pose2 * pmd3surf->numverts; if (surface_transparent) { sceGuEnable (GU_BLEND); //sceGuBlendFunc (GL_ONE, GL_ONE); sceGuDepthMask (GU_TRUE); sceGuDisable (GU_CULL_FACE); } else if (ISADDITIVE(ent)) sceGuEnable (GU_BLEND); // Allocate the vertices. struct vertex { float u, v; unsigned int color; float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * numtris)); for (i=0 ; ivec, v2->vec, distance) ? ent->framelerp : 1; l = FloatInterpolate (shadedots[v1->oldnormal>>8], lerpfrac, shadedots[v2->oldnormal>>8]); l = l / 256; l = fmin(l, 1); VectorInterpolate (v1->vec, lerpfrac, v2->vec, interpolated_verts); out[i].x = interpolated_verts[0]; out[i].y = interpolated_verts[1]; out[i].z = interpolated_verts[2]; for (j = 0 ; j < 3 ; j++) lightvec[j] = lightcolor[j] /1.0f + l; out[i].color = GU_COLOR(lightvec[0], lightvec[1], lightvec[2], 1.0f); *tris++; } if(r_showtris.value) { sceGuDisable(GU_TEXTURE_2D); } sceGuDrawArray(r_showtris.value ? GU_LINE_STRIP : GU_TRIANGLES, GU_TEXTURE_32BITF | GU_VERTEX_32BITF | GU_COLOR_8888, numtris, 0, out); if(r_showtris.value) { sceGuEnable(GU_TEXTURE_2D); } if (surface_transparent) { sceGuDisable (GU_BLEND); sceGuBlendFunc (GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDepthMask (GU_FALSE); sceGuEnable (GU_CULL_FACE); } else if (ISADDITIVE(ent)) sceGuDisable (GU_BLEND); } /* ================= R_DrawQ3Shadow ================= */ void R_DrawQ3Shadow (entity_t *ent, float lheight, float s1, float c1, trace_t downtrace) { int i, j, numtris, pose1, pose2; vec3_t point1, point2, interpolated; md3header_t *pmd3hdr; md3surface_t *pmd3surf; unsigned int *tris; md3vert_mem_t *verts; model_t *clmodel = ent->model; #if 0 float m[16]; md3tag_t *tag; tagentity_t *tagent; #endif pmd3hdr = (md3header_t *)Mod_Extradata (clmodel); pmd3surf = (md3surface_t *)((byte *)pmd3hdr + pmd3hdr->ofssurfs); for (i=0 ; inumsurfs ; i++) { verts = (md3vert_mem_t *)((byte *)pmd3hdr + pmd3surf->ofsverts); tris = (unsigned int *)((byte *)pmd3surf + pmd3surf->ofstris); numtris = pmd3surf->numtris * 3; pose1 = ent->pose1 * pmd3surf->numverts; pose2 = ent->pose2 * pmd3surf->numverts; // Allocate the vertices. struct vertex { float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * numtris)); for (j=0 ; jframelerp, point2, interpolated); interpolated[2] = -(ent->origin[2] - downtrace.endpos[2]); interpolated[2] += ((interpolated[1] * (s1 * downtrace.plane.normal[0])) - (interpolated[0] * (c1 * downtrace.plane.normal[0])) - (interpolated[0] * (s1 * downtrace.plane.normal[1])) - (interpolated[1] * (c1 * downtrace.plane.normal[1]))) + ((1 - downtrace.plane.normal[2]) * 20) + 0.2; out[j].x = interpolated[0]; out[j].y = interpolated[1]; out[j].z = interpolated[2]; *tris++; } if(r_showtris.value) { sceGuDisable(GU_TEXTURE_2D); } sceGuDrawArray(r_showtris.value ? GU_LINE_STRIP : GU_TRIANGLES,GU_VERTEX_32BITF, numtris, 0, out); if(r_showtris.value) { sceGuEnable(GU_TEXTURE_2D); } pmd3surf = (md3surface_t *)((byte *)pmd3surf + pmd3surf->ofsend); } if (!pmd3hdr->numtags) // single model, done return; // no multimodel shadow support yet #if 0 tag = (md3tag_t *)((byte *)pmd3hdr + pmd3hdr->ofstags); tag += ent->pose2 * pmd3hdr->numtags; for (i=0 ; inumtags ; i++, tag++) { if (multimodel_level == 0 && !strcmp(tag->name, "tag_torso")) { tagent = &q3player_body; ent = &q3player_body.ent; multimodel_level++; } else if (multimodel_level == 1 && !strcmp(tag->name, "tag_head")) { tagent = &q3player_head; ent = &q3player_head.ent; multimodel_level++; } else { continue; } glPushMatrix (); R_RotateForTagEntity (tagent, tag, m); glMultMatrixf (m); R_DrawQ3Shadow (ent, lheight, s1, c1, downtrace); glPopMatrix (); } #endif } /* ================= R_SetupQ3Frame ================= */ void R_SetupQ3Frame (entity_t *ent) { int i, j, frame, shadernum, texture; float m[16]; md3header_t *pmd3hdr; md3surface_t *pmd3surf; md3tag_t *tag; model_t *clmodel = ent->model; tagentity_t *tagent; if (!strcmp(clmodel->name, "models/player/lower.md3")) frame = legsframe; else if (!strcmp(clmodel->name, "models/player/upper.md3")) frame = bodyframe; else frame = ent->frame; // locate the proper data pmd3hdr = (md3header_t *)Mod_Extradata (clmodel); // draw all the triangles // draw non-transparent surfaces first, then the transparent ones for (i=0 ; i<2 ; i++) { pmd3surf = (md3surface_t *)((byte *)pmd3hdr + pmd3hdr->ofssurfs); for (j=0 ; jnumsurfs ; j++) { md3shader_mem_t *shader; surface_transparent = (strstr(pmd3surf->name, "energy") || strstr(pmd3surf->name, "f_") || strstr(pmd3surf->name, "flare") || strstr(pmd3surf->name, "flash") || strstr(pmd3surf->name, "Sphere") || strstr(pmd3surf->name, "telep")); if ((!i && surface_transparent) || (i && !surface_transparent)) { pmd3surf = (md3surface_t *)((byte *)pmd3surf + pmd3surf->ofsend); continue; } c_md3_polys += pmd3surf->numtris; shadernum = ent->skinnum; if ((shadernum >= pmd3surf->numshaders) || (shadernum < 0)) { Con_DPrintf ("R_SetupQ3Frame: no such skin # %d\n", shadernum); shadernum = 0; } shader = (md3shader_mem_t *)((byte *)pmd3hdr + pmd3surf->ofsshaders); texture = shader[shadernum].gl_texnum; //glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_Bind (texture); R_DrawQ3Frame (frame, pmd3hdr, pmd3surf, ent, INTERP_MAXDIST); pmd3surf = (md3surface_t *)((byte *)pmd3surf + pmd3surf->ofsend); } } if (!pmd3hdr->numtags) // single model, done return; tag = (md3tag_t *)((byte *)pmd3hdr + pmd3hdr->ofstags); tag += frame * pmd3hdr->numtags; for (i=0 ; inumtags ; i++, tag++) { if (multimodel_level == 0 && !strcmp(tag->name, "tag_torso")) { tagent = &q3player_body; ent = &q3player_body.ent; multimodel_level++; } else if (multimodel_level == 1 && !strcmp(tag->name, "tag_head")) { tagent = &q3player_head; ent = &q3player_head.ent; multimodel_level++; } else { continue; } sceGumPushMatrix (); R_RotateForTagEntity (tagent, tag, m); ConvertMatrix((float*)&md3mult, m); sceGumMultMatrix(&md3mult); sceGumUpdateMatrix (); R_SetupQ3Frame (ent); sceGumPopMatrix (); } } extern cvar_t scr_fov; /* ================= R_DrawQ3Model ================= */ void R_DrawQ3Model (entity_t *ent) { vec3_t mins, maxs, md3_scale_origin = {0, 0, 0}; model_t *clmodel = ent->model; float scale; int lnum; vec3_t dist; float add, an; VectorAdd (ent->origin, clmodel->mins, mins); VectorAdd (ent->origin, clmodel->maxs, maxs); if(ISADDITIVE(ent)) { float deg = ent->renderamt; float alpha_val = deg; float alpha_val2 = 1 - deg; if(deg <= 0.7) sceGuDepthMask(GU_TRUE); sceGuEnable (GU_BLEND); sceGuBlendFunc(GU_ADD, GU_FIX, GU_FIX, GU_COLOR(alpha_val,alpha_val,alpha_val,alpha_val), GU_COLOR(alpha_val2,alpha_val2,alpha_val2,alpha_val2)); } else if(ISGLOW(ent)) { sceGuDepthMask(GU_TRUE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_FIX, 0, 0xFFFFFFFF); sceGuTexFunc(GU_TFX_MODULATE , GU_TCC_RGB); } else if (ISSOLID(ent)) { sceGuEnable(GU_ALPHA_TEST); float c = (ent->renderamt) * 255.0f; sceGuAlphaFunc(GU_GREATER, 0x88, c); } if (ent->angles[0] || ent->angles[1] || ent->angles[2]) { if (R_CullSphere(ent->origin, clmodel->radius)) return; } else { if (R_CullBox(mins, maxs) == 2) return; } //========================================================================== VectorCopy (ent->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // R_LightPoint(currententity->origin); // LordHavoc: lightcolor is all that matters from this for (lnum=0 ; lnum= cl.time) { VectorSubtract (currententity->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - Length(dist); if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].color[0]; lightcolor[1] += add * cl_dlights[lnum].color[1]; lightcolor[2] += add * cl_dlights[lnum].color[2]; } } } // clamp lighting so it doesn't overbright as much //ColorClamp(lightcolor[0], lightcolor[1], lightcolor[2], 0, 125, 8); for(int g = 0; g < 3; g++) { if(lightcolor[g] < 8) lightcolor[g] = 8; if(lightcolor[g] > 125) lightcolor[g] = 125; } shadedots = r_avertexnormal_dots[((int)(ent->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); an = ent->angles[1]/180*M_PI; shadevector[0] = cosf(-an); shadevector[1] = sinf(-an); shadevector[2] = 1; VectorNormalize (shadevector); //========================================================================== sceGumPushMatrix (); if (ent == &cl.viewent) R_RotateForViewEntity (ent); else R_RotateForEntity(ent, 0, ent->scale); if ((ent == &cl.viewent) && (scr_fov.value != 0)) { if (scr_fov.value <= 90) scale = 1.0f; else #ifdef PSP_VFPU scale = 1.0f / vfpu_tanf( DEG2RAD(scr_fov.value/2)); #else scale = 1.0f / tan( DEG2RAD(scr_fov.value/2)); #endif const ScePspFVector3 translation = { md3_scale_origin[0]*scale, md3_scale_origin[1], md3_scale_origin[2] }; sceGumTranslate(&translation); const ScePspFVector3 GUscale = { scale, 1, 1 }; sceGumScale(&GUscale); } else { const ScePspFVector3 translation = { md3_scale_origin[0], md3_scale_origin[1], md3_scale_origin[2] }; sceGumTranslate(&translation); } sceGuShadeModel (GU_SMOOTH); sceGumUpdateMatrix (); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); //========================================================================== if ((!strcmp(ent->model->name, "models/player/lower.md3"))||(!strcmp(ent->model->name, "models/player/upper.md3"))) { //q3player_body.ent.renderamt = q3player_head.ent.renderamt = cl_entities[cl.viewentity].renderamt; R_ReplaceQ3Frame (ent->frame); ent->noshadow = qtrue; } multimodel_level = 0; R_SetupQ3Frame (ent); sceGuShadeModel (GU_FLAT); sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA); sceGumPopMatrix (); sceGumUpdateMatrix (); if (r_shadows.value && !ent->noshadow) { int farclip; float theta, lheight, s1, c1; vec3_t downmove; trace_t downtrace; static float shadescale = 0; farclip = fmax((int)r_farclip.value, 4096); if (!shadescale) shadescale = 1 / sqrt(2); theta = -ent->angles[1] / 180 * M_PI; #ifdef PSP_VFPU VectorSet (shadevector, cos(theta) * shadescale, vfpu_sinf(theta) * shadescale, shadescale); #else VectorSet (shadevector, cos(theta) * shadescale, sin(theta) * shadescale, shadescale); #endif sceGumPushMatrix (); R_RotateForEntity (ent, 0, ent->scale); VectorCopy (ent->origin, downmove); downmove[2] -= farclip; memset (&downtrace, 0, sizeof(downtrace)); SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, ent->origin, downmove, &downtrace); lheight = ent->origin[2] - lightspot[2]; #ifdef PSP_VFPU s1 = vfpu_sinf(ent->angles[1] / 180 * M_PI); c1 = vfpu_cosf(ent->angles[1] / 180 * M_PI); #else s1 = sin(ent->angles[1] / 180 * M_PI); c1 = cos(ent->angles[1] / 180 * M_PI); #endif sceGuDepthMask (GU_TRUE); sceGuDisable (GU_TEXTURE_2D); sceGuEnable (GU_BLEND); sceGuColor(GU_RGBA( static_cast(0.0f * 255.0f), static_cast(0.0f * 255.0f), static_cast(0.0f * 255.0f), static_cast(((ambientlight - (mins[2] - downtrace.endpos[2]))*r_shadows.value)*0.0066 * 255.0f))); multimodel_level = 0; sceGuEnable(GU_STENCIL_TEST); sceGuStencilFunc(GU_EQUAL,1,2); sceGuStencilOp(GU_KEEP,GU_KEEP,GU_INCR); R_DrawQ3Shadow (ent, lheight, s1, c1, downtrace); sceGuDisable(GU_STENCIL_TEST); sceGuDepthMask (GU_FALSE); sceGuEnable (GU_TEXTURE_2D); sceGuDisable (GU_BLEND); sceGuColor(GU_RGBA(0xff,0xff,0xff,0xff)); //return to normal color sceGumPopMatrix (); sceGumUpdateMatrix (); } if (ISADDITIVE(ent)) { float deg = ent->renderamt; if(deg <= 0.7) sceGuDepthMask(GU_FALSE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDisable (GU_BLEND); } else if(ISSOLID(ent)) { sceGuAlphaFunc(GU_GREATER, 0, 0xff); sceGuDisable(GU_ALPHA_TEST); } else if(ISGLOW(ent)) { sceGuDepthMask(GU_FALSE); sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); sceGuDisable (GU_BLEND); } } /* ============= R_DrawNullModel From pspq2 ============= */ void R_DrawNullModel(void) { R_LightPoint(currententity->origin); sceGumPushMatrix(); sceGuDisable(GU_TEXTURE_2D); sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); sceGuShadeModel (GU_SMOOTH); R_RotateForEntity(currententity, 0, currententity->scale); typedef struct VERT_t { float x, y, z; } VERT; VERT* v; sceGuColor(0x0099FF); v = (VERT*)sceGuGetMemory(sizeof(VERT) * 6); v[0].x = 0.0f; v[0].y = 0.0f; v[0].z = 9.0f; v[1].x = 9.0f; v[1].y = 0.0f; v[1].z = 0.0f; v[2].x = 0.0f; v[2].y = -9.0f; v[2].z = 0.0f; v[3].x = -9.0f; v[3].y = 0.0f; v[3].z = 0.0f; v[4].x = 0.0f; v[4].y = 9.0f; v[4].z = 0.0f; v[5].x = 9.0f; v[5].y = 0.0f; v[5].z = 0.0f; sceGumDrawArray(r_showtris.value ? GU_LINE_STRIP : GU_TRIANGLE_FAN, GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, v); sceGuColor(0x0000FF); v = (VERT*)sceGuGetMemory(sizeof(VERT) * 6); v[0].x = 0.0f; v[0].y = 0.0f; v[0].z = -9.0f; v[1].x = 9.0f; v[1].y = 0.0f; v[1].z = 0.0f; v[2].x = 0.0f; v[2].y = 9.0f; v[2].z = 0.0f; v[3].x = -9.0f; v[3].y = 0.0f; v[3].z = 0.0f; v[4].x = 0.0f; v[4].y = -9.0f; v[4].z = 0.0f; v[5].x = 9.0f; v[5].y = 0.0f; v[5].z = 0.0f; sceGumDrawArray(r_showtris.value ? GU_LINE_STRIP : GU_TRIANGLE_FAN, GU_VERTEX_32BITF | GU_TRANSFORM_3D, 6, 0, v); sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA); sceGuColor(0xFFFFFF); sceGuEnable(GU_TEXTURE_2D); sceGumPopMatrix(); } /* ================ R_EmitWireBox -- johnfitz -- draws one axis aligned bounding box ================ */ void R_EmitWireBox (vec3_t mins, vec3_t maxs,qboolean line_strip) { // Allocate the vertices. struct vertex { float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * 10)); out[0].x = mins[0]; out[0].y = mins[1]; out[0].z = mins[2]; out[1].x = mins[0]; out[1].y = mins[1]; out[1].z = maxs[2]; out[2].x = maxs[0]; out[2].y = mins[1]; out[2].z = mins[2]; out[3].x = maxs[0]; out[3].y = mins[1]; out[3].z = maxs[2]; out[4].x = maxs[0]; out[4].y = maxs[1]; out[4].z = mins[2]; out[5].x = maxs[0]; out[5].y = maxs[1]; out[5].z = maxs[2]; out[6].x = mins[0]; out[6].y = maxs[1]; out[6].z = mins[2]; out[7].x = mins[0]; out[7].y = maxs[1]; out[7].z = maxs[2]; out[8].x = mins[0]; out[8].y = mins[1]; out[8].z = mins[2]; out[9].x = mins[0]; out[9].y = mins[1]; out[9].z = maxs[2]; sceGuDrawArray(line_strip ? GU_LINE_STRIP : GU_TRIANGLE_STRIP,GU_VERTEX_32BITF, 10, 0, out); } void R_DrawLine(vec3_t start,vec3_t end, vec3_t rgb) { //Do Before! sceGuDisable (GU_TEXTURE_2D); sceGuDisable (GU_CULL_FACE); sceGuColor(GU_COLOR(rgb[0],rgb[1],rgb[2],1)); // Allocate the vertices. struct vertex { float x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * 2));//10 out[0].x = start[0]; out[0].y = start[1]; out[0].z = start[2]; out[1].x = end[0]; out[1].y = end[1]; out[1].z = end[2]; sceGuDrawArray(GU_LINE_STRIP,GU_VERTEX_32BITF, 2, 0, out); //Do After! sceGuColor(GU_COLOR(1,1,1,1)); sceGuEnable (GU_TEXTURE_2D); sceGuEnable (GU_CULL_FACE); } //================================================================================== int SetFlameModelState (void) { if (!r_part_flames.value && !strcmp(currententity->model->name, "progs/flame0.mdl")) { currententity->model = cl.model_precache[cl_modelindex[mi_flame1]]; } else if (r_part_flames.value) { vec3_t liteorg; VectorCopy (currententity->origin, liteorg); if (currententity->baseline.modelindex == cl_modelindex[mi_flame0]) { if (r_part_flames.value == 2) { liteorg[2] += 14; QMB_Q3TorchFlame (liteorg, 15); } else { liteorg[2] += 5.5; if(r_flametype.value == 2) QMB_FlameGt (liteorg, 7, 0.8); else QMB_TorchFlame(liteorg); } } else if (currententity->baseline.modelindex == cl_modelindex[mi_flame1]) { if (r_part_flames.value == 2) { liteorg[2] += 14; QMB_Q3TorchFlame (liteorg, 15); } else { liteorg[2] += 5.5; if(r_flametype.value > 1) QMB_FlameGt (liteorg, 7, 0.8); else QMB_TorchFlame(liteorg); } currententity->model = cl.model_precache[cl_modelindex[mi_flame0]]; } else if (currententity->baseline.modelindex == cl_modelindex[mi_flame2]) { if (r_part_flames.value == 2) { liteorg[2] += 14; QMB_Q3TorchFlame (liteorg, 32); } else { liteorg[2] -= 1; if(r_flametype.value > 1) QMB_FlameGt (liteorg, 12, 1); else QMB_BigTorchFlame(liteorg); } return -1; //continue; } else if (!strcmp(currententity->model->name, "progs/wyvflame.mdl")) { liteorg[2] -= 1; if(r_flametype.value > 1) QMB_FlameGt (liteorg, 12, 1); else QMB_BigTorchFlame(liteorg); return -1; //continue; } } return 0; } /* ============= R_DrawEntitiesOnList ============= */ void R_DrawEntitiesOnList (void) { int i; if (!r_drawentities.value) return; //t1 = 0; //t2 = 0; //t3 = 0; //t1 -= Sys_FloatTime(); int zHackCount = 0; doZHack = 0; char specChar; // draw sprites seperately, because of alpha blending for (i=0 ; iangles[0] *= 0.3; //currentmodel = currententity->model; if(!(currententity->model)) { R_DrawNullModel(); continue; } specChar = currententity->model->name[strlen(currententity->model->name)-5]; if(specChar == '(' || specChar == '^')//skip heads and arms: it's faster to do this than a strcmp... { continue; } doZHack = 0; if(specChar == '%') { if(zHackCount > 5 || ((currententity->z_head != 0) && (currententity->z_larm != 0) && (currententity->z_rarm != 0))) { doZHack = 1; } else { zHackCount ++;//drawing zombie piece by piece. } } switch (currententity->model->type) { case mod_alias: if (qmb_initialized && SetFlameModelState() == -1) continue; if (currententity->model->aliastype == ALIASTYPE_MD2) R_DrawMD2Model (currententity); else { if(specChar == '$')//This is for smooth alpha, draw in the following loop, not this one { continue; } R_DrawAliasModel (currententity); } break; case mod_md3: R_DrawQ3Model (currententity); break; case mod_halflife: R_DrawHLModel (currententity); break; case mod_brush: R_DrawBrushModel (currententity); break; default: break; } doZHack = 0; } for (i=0 ; imodel)) { continue; } specChar = currententity->model->name[strlen(currententity->model->name)-5]; switch (currententity->model->type) { case mod_sprite: { R_DrawSpriteModel (currententity); break; } case mod_alias: if (currententity->model->aliastype != ALIASTYPE_MD2) { if(specChar == '$')//mdl model with blended alpha { R_DrawTransparentAliasModel(currententity); } } break; default: break; } } } /* ============= R_DrawViewModel ============= */ void R_DrawViewModel (void) { /* float ambient[4], diffuse[4]; int j; int lnum; vec3_t dist; float add; dlight_t *dl; int ambientlight, shadelight; */ // fenix@io.com: model transform interpolation float old_i_model_transform; if (!r_drawviewmodel.value) return; if (chase_active.value) return; if (envmap) return; if (!r_drawentities.value) return; /*if (cl.items & IT_INVISIBILITY) return;*/ if (cl.stats[STAT_HEALTH] < 0) return; currententity = &cl.viewent; if (!currententity->model) return; // Tomaz - QC Alpha Scale Begin currententity->renderamt = cl_entities[cl.viewentity].renderamt; currententity->rendermode = cl_entities[cl.viewentity].rendermode; currententity->rendercolor[0] = cl_entities[cl.viewentity].rendercolor[0]; currententity->rendercolor[1] = cl_entities[cl.viewentity].rendercolor[1]; currententity->rendercolor[2] = cl_entities[cl.viewentity].rendercolor[2]; // Tomaz - QC Alpha Scale End /* j = R_LightPoint (currententity->origin); if (j < 24) j = 24; // allways give some light on gun ambientlight = j; shadelight = j; // add dynamic lights for (lnum=0 ; lnumradius) continue; if (!dl->radius) continue; if (dl->die < cl.time) continue; VectorSubtract (currententity->origin, dl->origin, dist); add = dl->radius - Length(dist); if (add > 0) ambientlight += add; } */ /* ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; */ // hack the depth range to prevent view model from poking into walls sceGuDepthRange(0, 19660); //Blubs' tests for vmodel clipping //sceGuDisable(GU_CLIP_PLANES); //sceGuDisable(GU_DEPTH_TEST); //sceGuDisable(GU_CULL_FACE); //sceGuDisable(GU_SCISSOR_TEST); switch (currententity->model->type) { case mod_alias: // fenix@io.com: model transform interpolation old_i_model_transform = r_i_model_transform.value; r_i_model_transform.value = false; if (currententity->model->aliastype == ALIASTYPE_MD2) R_DrawMD2Model (currententity); else R_DrawAliasModel (currententity); r_i_model_transform.value = old_i_model_transform; break; case mod_md3: R_DrawQ3Model (currententity); break; case mod_halflife: R_DrawHLModel (currententity); break; default: Con_Printf("Not drawing view model of type %i\n", currententity->model->type); break; } //sceGuEnable(GU_SCISSOR_TEST); //sceGuEnable(GU_DEPTH_TEST); //sceGuEnable(GU_CLIP_PLANES); //sceGuEnable(GU_CULL_FACE); sceGuDepthRange(0, 65535); sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuDisable(GU_BLEND); } /* ============= R_DrawView2Model ============= */ void R_DrawView2Model (void) { float old_i_model_transform; if (!r_drawviewmodel.value) return; if (chase_active.value) return; if (envmap) return; if (!r_drawentities.value) return; if (cl.stats[STAT_HEALTH] < 0) return; currententity = &cl.viewent2; if (!currententity->model) return; // Tomaz - QC Alpha Scale Begin currententity->renderamt = cl_entities[cl.viewentity].renderamt; currententity->rendermode = cl_entities[cl.viewentity].rendermode; currententity->rendercolor[0] = cl_entities[cl.viewentity].rendercolor[0]; currententity->rendercolor[1] = cl_entities[cl.viewentity].rendercolor[1]; currententity->rendercolor[2] = cl_entities[cl.viewentity].rendercolor[2]; // hack the depth range to prevent view model from poking into walls sceGuDepthRange(0, 19660); switch (currententity->model->type) { case mod_alias: // fenix@io.com: model transform interpolation old_i_model_transform = r_i_model_transform.value; r_i_model_transform.value = false; if (currententity->model->aliastype == ALIASTYPE_MD2) R_DrawMD2Model (currententity); else R_DrawAliasModel (currententity); r_i_model_transform.value = old_i_model_transform; break; case mod_md3: R_DrawQ3Model (currententity); break; case mod_halflife: R_DrawHLModel (currententity); break; default: Con_Printf("Not drawing view model of type %i\n", currententity->model->type); break; } sceGuDepthRange(0, 65535); sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); sceGuDisable(GU_BLEND); } /* ============ R_PolyBlend ============ */ void R_PolyBlend (void) { if (!r_polyblend.value) return; if (!v_blend[3]) return; sceGuEnable (GU_BLEND); sceGuDisable (GU_TEXTURE_2D); sceGuTexFunc (GU_TFX_MODULATE, GU_TCC_RGBA); sceGumLoadIdentity(); sceGuColor(GU_COLOR(v_blend[0], v_blend[1], v_blend[2], v_blend[3])); struct vertex { short x, y, z; }; vertex* const out = static_cast(sceGuGetMemory(sizeof(vertex) * 2)); out[0].x = 0; out[0].y = 0; out[0].z = 0; out[1].x = 480; out[1].y = 272; out[1].z = 0; sceGuDrawArray(GU_SPRITES, GU_VERTEX_16BIT | GU_TRANSFORM_2D, 2, 0, out); sceGuColor(0xffffffff); sceGuDisable (GU_BLEND); sceGuEnable (GU_TEXTURE_2D); sceGuTexFunc (GU_TFX_REPLACE, GU_TCC_RGBA); } static int SignbitsForPlane (mplane_t *out) { int bits, j; // for fast box on planeside test bits = 0; for (j=0 ; j<3 ; j++) { if (out->normal[j] < 0) bits |= 1< 1) Cvar_Set ("r_fullbright", "0"); //xaa - opt int w_ratio = glwidth/vid.width; int h_ratio = glheight/vid.height; vrect_t* renderrect = &r_refdef.vrect; //setupframe Fog_SetupFrame(false); R_AnimateLight(); ++r_framecount; VectorCopy (r_refdef.vieworg, r_origin); AngleVectors (r_refdef.viewangles, vpn, vright, vup); // current viewleaf r_oldviewleaf = r_viewleaf; r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); V_SetContentsColor (r_viewleaf->contents); V_CalcBlend (); c_brush_polys = 0; c_alias_polys = 0; c_md3_polys = 0; //setfrustum // disabled as well if (r_refdef.fov_x == 90) { // front side is visible VectorAdd(vpn, vright, frustum[0].normal); VectorSubtract(vpn, vright, frustum[1].normal); VectorAdd(vpn, vright, frustum[1].normal); VectorSubtract(vpn, vup, frustum[3].normal); } else { RotatePointAroundVector( frustum[0].normal, vup, vpn, -( vecx_point_transform ) ); RotatePointAroundVector( frustum[1].normal, vup, vpn, ( vecx_point_transform ) ); RotatePointAroundVector( frustum[2].normal, vright, vpn, ( vecy_point_transform ) ); RotatePointAroundVector( frustum[3].normal, vright, vpn, -( vecy_point_transform ) ); } for (i=0 ; i<4 ; i++) { frustum[i].type = PLANE_ANYZ; frustum[i].dist = DotProduct (r_origin, frustum[i].normal); frustum[i].signbits = SignbitsForPlane (&frustum[i]); } //setupgl // set up viewpoint sceGumMatrixMode(GU_PROJECTION); sceGumLoadIdentity(); x = renderrect->x * w_ratio; x2 = (renderrect->x + renderrect->width) * w_ratio; y = (vid.height-renderrect->y) * h_ratio; y2 = (vid.height - (renderrect->y + renderrect->height)) * h_ratio; // fudge around because of frac screen scale if (x > 0) x--; if (x2 < glwidth) x2++; if (y2 < 0) y2--; if (y < glheight) y++; w = x2 - x; h = y - y2; if (envmap) { x = y2 = 0; w = h = 256; } sceGuViewport( glx, gly + (glheight >> 1) - y2 - (h >> 1), //xaa - try to skip some divides (/2) here w, h); sceGuScissor(x, glheight - y2 - h, x + w, glheight - y2); screenaspect = (float)renderrect->width/renderrect->height; //johnfitz -- warp view for underwater fovx = screenaspect; fovy = r_refdef.fov_y; if (r_waterwarp.value) { contents = Mod_PointInLeaf (r_origin, cl.worldmodel)->contents; if (contents == CONTENTS_WATER || contents == CONTENTS_SLIME || contents == CONTENTS_LAVA) { //variance should be a percentage of width, where width = 2 * tan(fov / 2) //otherwise the effect is too dramatic at high FOV and too subtle at low FOV //what a mess! //fovx = atan(tan(DEG2RAD(r_refdef.fov_x) / 2) * (0.97 + sin(cl.time * 1) * 0.04)) * 2 / M_PI_DIV_180; #ifdef PSP_VFPU fovy = RAD2DEG(vfpu_atanf(vfpu_tanf(DEG2RAD(r_refdef.fov_y) / 2) * (1.03 - vfpu_sinf(cl.time * 2) * 0.04))); #else fovy = RAD2DEG(atan(tan(DEG2RAD(r_refdef.fov_y) / 2) * (1.03 - sin(cl.time * 2) * 0.04))); #endif } } float farplanedist = (r_refdef.fog_start == 0 || r_refdef.fog_end < 0) ? 4096 : (r_refdef.fog_end + 16); sceGumPerspective(fovy, fovx, 4, farplanedist); if (mirror) { if (mirror_plane->normal[2]) { const ScePspFVector3 scaling = {1, -1, 1}; sceGumScale(&scaling); } else { const ScePspFVector3 scaling = {-1, 1, 1}; sceGumScale(&scaling); } } sceGumUpdateMatrix(); sceGumMatrixMode(GU_VIEW); sceGumLoadIdentity(); sceGumRotateX(-90 * piconst); sceGumRotateZ(90 * piconst); sceGumRotateX(-r_refdef.viewangles[2] * piconst); sceGumRotateY(-r_refdef.viewangles[0] * piconst); sceGumRotateZ(-r_refdef.viewangles[1] * piconst); /*glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]);*/ const ScePspFVector3 translation = { -r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2] }; sceGumTranslate(&translation); /*glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);*/ sceGumStoreMatrix(&r_world_matrix); sceGumUpdateMatrix(); sceGumMatrixMode(GU_MODEL); // the value 2.2 is a bit of a sweet spot found by trial and error // the bigger the number, the more polys skip clipping entirely and less polys also rejected // the smaller the number, the more polys get clipped and by extension more polys also rejected // at a sweet spot we want to maximize rejected polys but minimize (clipped - rejected) amount at the same time // it's a balancing act and every change has to be benchmarked. between 2.5, 2.2 and 2.0, 2.2 was the fastest. clipping::begin_frame(fovy, fmin(165.f, fovy * 2.2f), fovx); sceGumMatrixMode(GU_PROJECTION); sceGumLoadIdentity(); sceGumPerspective(fovy, fovx, 4, farplanedist); sceGumUpdateMatrix(); sceGumMatrixMode(GU_MODEL); // set drawing parms sceGuDisable(GU_BLEND); sceGuDisable(GU_ALPHA_TEST); sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); R_MarkLeaves (); // done here so we know if we're in water Fog_EnableGFog (); //johnfitz R_DrawWorld (); // adds static entities to the list S_ExtraUpdate (); // don't let sound get messed up if going slow R_DrawEntitiesOnList(); R_RenderDlights (); //pointless jump? -xaa R_DrawDecals(); R_DrawParticles (); Fog_DisableGFog (); //johnfitz } /* ============= R_Clear ============= */ extern char skybox_name[32]; void R_Clear (void) { if(r_refdef.fog_end > 0 && r_skyfog.value) { sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT); sceGuClearColor(GU_COLOR(r_refdef.fog_red * 0.01f,r_refdef.fog_green * 0.01f,r_refdef.fog_blue * 0.01f,1.0f)); } else { if (!skybox_name[0]) { byte *sky_color = StringToRGB (r_skycolor.string); sceGuClearColor(GU_RGBA(sky_color[0], sky_color[1], sky_color[2], 255)); } sceGuClear(GU_COLOR_BUFFER_BIT | GU_DEPTH_BUFFER_BIT); } if(r_shadows.value) { sceGuClearStencil(GU_TRUE); sceGuClear(GU_STENCIL_BUFFER_BIT); } } /* ============= R_Mirror ============= */ void R_Mirror (void) { float d; msurface_t *s; entity_t *ent; if (!mirror) return; r_base_world_matrix = r_world_matrix; d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); d = DotProduct (vpn, mirror_plane->normal); VectorMA (vpn, -2*d, mirror_plane->normal, vpn); r_refdef.viewangles[0] = -asinf(vpn[2])/M_PI*180; r_refdef.viewangles[1] = atan2f(vpn[1], vpn[0])/M_PI*180; r_refdef.viewangles[2] = -r_refdef.viewangles[2]; ent = &cl_entities[cl.viewentity]; if (cl_numvisedicts < MAX_VISEDICTS) { cl_visedicts[cl_numvisedicts] = ent; cl_numvisedicts++; } R_RenderScene (); R_DrawWaterSurfaces (); // blend on top sceGuEnable (GU_BLEND); sceGumMatrixMode(GU_PROJECTION); sceGumLoadIdentity(); if (mirror_plane->normal[2]) { const ScePspFVector3 scaling = {1, -1, 1}; sceGumScale(&scaling); } else { const ScePspFVector3 scaling = {-1, 1, 1}; sceGumScale(&scaling); } //sceGuFrontFace(GU_CW); sceGumMatrixMode(GU_VIEW); sceGumLoadIdentity(); sceGumMatrixMode(GU_MODEL); sceGumStoreMatrix(&r_base_world_matrix); sceGumUpdateMatrix(); sceGuColor(GU_COLOR(1,1,1,r_mirroralpha.value)); s = cl.worldmodel->textures[mirrortexturenum]->texturechain; for ( ; s ; s=s->texturechain) R_RenderBrushPoly (s); cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; sceGuDisable (GU_BLEND); sceGuColor (0xffffffff); } /* ================ R_RenderView r_refdef must be set before the first call ================ */ void R_RenderView (void) { c_brush_polys = 0; c_alias_polys = 0; c_md3_polys = 0; mirror = qfalse; R_Clear (); // render normal view R_RenderScene (); R_DrawViewModel (); R_DrawView2Model (); R_DrawWaterSurfaces (); // render mirror view R_Mirror (); R_PolyBlend (); //Crow_bar fixed if (r_speeds.value) { Con_Printf ("%4i world poly\n", c_brush_polys); Con_Printf ("%4i entity poly\n", c_alias_polys); } }