// // R_SortPolyObjects // // haleyjd 03/03/06: Here's the REAL meat of Eternity's polyobject system. // Hexen just figured this was impossible, but as mentioned in polyobj.c, // it is perfectly doable within the confines of the BSP tree. Polyobjects // must be sorted to draw in DOOM's front-to-back order within individual // subsectors. This is a modified version of R_SortVisSprites. // void R_SortPolyObjects(subsector_t *sub) { if (numpolys) { polyobj_t *po; INT32 i = 0; // allocate twice the number needed to minimize allocations if (num_po_ptrs < numpolys*2) { // use free instead realloc since faster (thanks Lee ^_^) free(po_ptrs); po_ptrs = malloc((num_po_ptrs = numpolys*2) * sizeof(*po_ptrs)); } po = sub->polyList; while (po) { po->zdist = R_PointToDist2(viewx, viewy, po->centerPt.x, po->centerPt.y); po_ptrs[i++] = po; po = (polyobj_t *)(po->link.next); } // the polyobjects are NOT in any particular order, so use qsort // 03/10/06: only bother if there are actually polys to sort if (numpolys >= 2) { qsort(po_ptrs, numpolys, sizeof(polyobj_t *), R_PolyobjCompare); } } }
// // R_PolysegCompare // // Callback for qsort to sort the segs of a polyobject. Returns such that the // closer one is sorted first. I sure hope this doesn't break anything. -Red // static int R_PolysegCompare(const void *p1, const void *p2) { const seg_t *seg1 = *(const seg_t * const *)p1; const seg_t *seg2 = *(const seg_t * const *)p2; fixed_t dist1v1, dist1v2, dist2v1, dist2v2; // TODO might be a better way to get distance? #define pdist(x, y) (FixedMul(R_PointToDist(x, y), FINECOSINE((R_PointToAngle(x, y)-viewangle)>>ANGLETOFINESHIFT))+0xFFFFFFF) #define vxdist(v) pdist(v->x, v->y) dist1v1 = vxdist(seg1->v1); dist1v2 = vxdist(seg1->v2); dist2v1 = vxdist(seg2->v1); dist2v2 = vxdist(seg2->v2); if (min(dist1v1, dist1v2) != min(dist2v1, dist2v2)) return min(dist1v1, dist1v2) - min(dist2v1, dist2v2); { // That didn't work, so now let's try this....... fixed_t delta1, delta2, x1, y1, x2, y2; vertex_t *near1, *near2, *far1, *far2; // wherever you are~ delta1 = R_PointToDist2(seg1->v1->x, seg1->v1->y, seg1->v2->x, seg1->v2->y); delta2 = R_PointToDist2(seg2->v1->x, seg2->v1->y, seg2->v2->x, seg2->v2->y); delta1 = FixedDiv(128<<FRACBITS, delta1); delta2 = FixedDiv(128<<FRACBITS, delta2); if (dist1v1 < dist1v2) { near1 = seg1->v1; far1 = seg1->v2; } else { near1 = seg1->v2; far1 = seg1->v1; } if (dist2v1 < dist2v2) { near2 = seg2->v1; far2 = seg2->v2; } else { near2 = seg2->v2; far2 = seg2->v1; } x1 = near1->x + FixedMul(far1->x-near1->x, delta1); y1 = near1->y + FixedMul(far1->y-near1->y, delta1); x2 = near2->x + FixedMul(far2->x-near2->x, delta2); y2 = near2->y + FixedMul(far2->y-near2->y, delta2); return pdist(x1, y1)-pdist(x2, y2); } #undef vxdist #undef pdist }
void GL_RenderPoly(gl_poly_t *poly) { FAnimDef *anim = NULL; // float alpha; // unsigned short tex1, tex2, curFrame; if (!poly->initialized) return; GL_BindArrays(poly); if (MaskSkybox) { glColor4f(1.f, 1.f, 1.f, 1.f); textureList.BindGLTexture(0); glDrawArrays(GL_TRIANGLE_FAN, 0, poly->numPts); } else { GL_SetupFog(poly->lightLevel, poly->fogR, poly->fogG, poly->fogB); // non-masked, so disable transparency if (!DrawingDeferredLines && poly->a == 1.f) { glDisable(GL_BLEND); } if (poly->doomTex > 0) { if (gl_blend_animations && gl_texture && !gl_wireframe && !textureList.IsTransparent()) { anim = GL_GetAnimForLump(poly->doomTex); } } else { return; } glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(poly->scaleX, poly->scaleY, 1.f); glTranslatef(poly->offX, poly->offY, 0.f); glRotatef(poly->rot, 0.f, 0.f, 1.f); glMatrixMode(GL_MODELVIEW); glColor4f(poly->r, poly->g, poly->b, poly->a); glDrawArrays(GL_TRIANGLE_FAN, 0, poly->numPts); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } numTris += poly->numPts - 2; if (r_fogboundary && poly->isFogBoundary) { #if 0 // draw poly again with depth-dependent alpha edges // note that fog boundaries are always walls, so they're always quads float a1, a2; fixed_t x, y, dist; int i; glDisable(GL_TEXTURE_2D); glAlphaFunc(GL_GREATER, 0.f); x = (fixed_t)(-poly->vertices[3] * MAP_SCALE); y = (fixed_t)(poly->vertices[5] * MAP_SCALE); dist = R_PointToDist2(x, y); a1 = dist / 384.f * INV_FRACUNIT; x = (fixed_t)(-poly->vertices[6] * MAP_SCALE); y = (fixed_t)(poly->vertices[8] * MAP_SCALE); dist = R_PointToDist2(x, y); a2 = dist / 384.f * INV_FRACUNIT; a1 *= 0.75f * byte2float[poly->fbLightLevel]; a2 *= 0.75f * byte2float[poly->fbLightLevel]; //a1 = 0.f; //a2 = 1.f; glColor4f(byte2float[poly->fbR] * byte2float[poly->fbLightLevel], byte2float[poly->fbG] * byte2float[poly->fbLightLevel], byte2float[poly->fbB] * byte2float[poly->fbLightLevel], a1 * a1); glBegin(GL_TRIANGLE_FAN); for (i = 0; i < poly->numPts; i++) { if (i == poly->numPts / 2) { glColor4f(byte2float[poly->fbR] * byte2float[poly->fbLightLevel], byte2float[poly->fbG] * byte2float[poly->fbLightLevel], byte2float[poly->fbB] * byte2float[poly->fbLightLevel], a2 * a2); } glVertex3fv(&poly->vertices[i * 3]); } glEnd(); glEnable(GL_TEXTURE_2D); #endif } // all this really does is potentially unlocks the vertex arrays GL_UnbindArrays(poly); }
void gl_RenderModel(GLSprite * spr, int cm) { // [BB/EP] Take care of gl_fogmode and ZADF_FORCE_GL_DEFAULTS. OVERRIDE_FOGMODE_IF_NECESSARY FSpriteModelFrame * smf = spr->modelframe; // Setup transformation. gl.MatrixMode(GL_MODELVIEW); gl.PushMatrix(); gl.DepthFunc(GL_LEQUAL); // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. // TO-DO: Implement proper depth sorting. if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) { gl.Enable(GL_CULL_FACE); glFrontFace(GL_CW); } int translation = 0; if ( !(smf->flags & MDL_IGNORETRANSLATION) ) translation = spr->actor->Translation; // y scale for a sprite means height, i.e. z in the world! float scaleFactorX = FIXED2FLOAT(spr->actor->scaleX) * smf->xscale; float scaleFactorY = FIXED2FLOAT(spr->actor->scaleX) * smf->yscale; float scaleFactorZ = FIXED2FLOAT(spr->actor->scaleY) * smf->zscale; float pitch = 0; float rotateOffset = 0; float angle = ANGLE_TO_FLOAT(spr->actor->angle); // [BB] Workaround for the missing pitch information. if ( (smf->flags & MDL_PITCHFROMMOMENTUM) ) { const double x = static_cast<double>(spr->actor->velx); const double y = static_cast<double>(spr->actor->vely); const double z = static_cast<double>(spr->actor->velz); // [BB] Calculate the pitch using spherical coordinates. pitch = float(atan( z/sqrt(x*x+y*y) ) / M_PI * 180); } if( smf->flags & MDL_ROTATING ) { const float time = smf->rotationSpeed*GetTimeFloat()/200.f; rotateOffset = float((time - xs_FloorToInt(time)) *360.f ); } if (gl_fogmode != 2 && (GLRenderer->mLightCount == 0 || !gl_light_models)) { // Model space => World space gl.Translatef(spr->x, spr->z, spr->y ); if ( !(smf->flags & MDL_ALIGNANGLE) ) gl.Rotatef(-angle, 0, 1, 0); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else gl.Rotatef( -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ), 0, 1, 0); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); gl.Rotatef(pitch, 0, 0, 1); } // [BB] Workaround for the missing pitch information. if (pitch != 0) gl.Rotatef(pitch, 0, 0, 1); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) gl.Rotatef( gl_RollAgainstAngleHelper ( spr->actor ), 1, 0, 0); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { gl.Translatef(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); gl.Rotatef(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); gl.Translatef(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); } // Scaling and model space offset. gl.Scalef(scaleFactorX, scaleFactorZ, scaleFactorY); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. gl.Translatef(0., smf->zoffset / smf->zscale, 0.); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, NULL, NULL, translation ); } else { Matrix3x4 ModelToWorld; Matrix3x4 NormalTransform; // For radial fog we need to pass coordinates in world space in order to calculate distances. // That means that the local transformations cannot be part of the modelview matrix ModelToWorld.MakeIdentity(); // Model space => World space ModelToWorld.Translate(spr->x, spr->z, spr->y); if ( !(smf->flags & MDL_ALIGNANGLE) ) ModelToWorld.Rotate(0,1,0, -angle); // [BB] Change the angle so that the object is exactly facing the camera in the x/y plane. else ModelToWorld.Rotate(0,1,0, -ANGLE_TO_FLOAT ( R_PointToAngle ( spr->actor->x, spr->actor->y ) ) ); // [BB] Change the pitch so that the object is vertically facing the camera (only makes sense combined with MDL_ALIGNANGLE). if ( (smf->flags & MDL_ALIGNPITCH) ) { const fixed_t distance = R_PointToDist2( spr->actor->x - viewx, spr->actor->y - viewy ); const float pitch = RAD2DEG ( atan2( FIXED2FLOAT ( spr->actor->z - viewz ), FIXED2FLOAT ( distance ) ) ); ModelToWorld.Rotate(0,0,1,pitch); } // [BB] Workaround for the missing pitch information. if (pitch != 0) ModelToWorld.Rotate(0,0,1,pitch); // [BB] Special flag for flat, beam like models. if ( (smf->flags & MDL_ROLLAGAINSTANGLE) ) ModelToWorld.Rotate(1, 0, 0, gl_RollAgainstAngleHelper ( spr->actor )); // Model rotation. // [BB] Added Doomsday like rotation of the weapon pickup models. // The rotation angle is based on the elapsed time. if( smf->flags & MDL_ROTATING ) { ModelToWorld.Translate(-smf->rotationCenterX, -smf->rotationCenterY, -smf->rotationCenterZ); ModelToWorld.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, rotateOffset); ModelToWorld.Translate(smf->rotationCenterX, smf->rotationCenterY, smf->rotationCenterZ); } ModelToWorld.Scale(scaleFactorX, scaleFactorZ, scaleFactorY); // [BB] Apply zoffset here, needs to be scaled by 1 / smf->zscale, so that zoffset doesn't depend on the z-scaling. ModelToWorld.Translate(0., smf->zoffset / smf->zscale, 0.); if (!gl_light_models) { gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, NULL, translation ); } else { // The normal transform matrix only contains the inverse rotations and scalings but not the translations NormalTransform.MakeIdentity(); NormalTransform.Scale(1.f/scaleFactorX, 1.f/scaleFactorZ, 1.f/scaleFactorY); if( smf->flags & MDL_ROTATING ) NormalTransform.Rotate(smf->xrotate, smf->yrotate, smf->zrotate, -rotateOffset); if (pitch != 0) NormalTransform.Rotate(0,0,1,-pitch); if (angle != 0) NormalTransform.Rotate(0,1,0, angle); gl_RenderFrameModels( smf, spr->actor->state, spr->actor->tics, RUNTIME_TYPE(spr->actor), cm, &ModelToWorld, &NormalTransform, translation ); } } gl.MatrixMode(GL_MODELVIEW); gl.PopMatrix(); gl.DepthFunc(GL_LESS); if (!( spr->actor->RenderStyle == LegacyRenderStyles[STYLE_Normal] )) gl.Disable(GL_CULL_FACE); }