/********* SP_DrawTexture *********/ void SP_DrawTexture(void* pixels, float width, float height, float vShift) { if (!pixels) { // Ug. We were not even able to load the error message texture. return; } // Create a texture from the buffered file GLuint texid; qglGenTextures(1, &texid); qglBindTexture(GL_TEXTURE_2D, texid); qglTexImage2D(GL_TEXTURE_2D, 0, GL_DDS1_EXT, width, height, 0, GL_DDS1_EXT, GL_UNSIGNED_BYTE, pixels); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); // Reset every GL state we've got. Who knows what state // the renderer could be in when this function gets called. qglColor3f(1.f, 1.f, 1.f); #ifdef _XBOX if(glw_state->isWidescreen) qglViewport(0, 0, 720, 480); else #endif qglViewport(0, 0, 640, 480); GLboolean alpha = qglIsEnabled(GL_ALPHA_TEST); qglDisable(GL_ALPHA_TEST); GLboolean blend = qglIsEnabled(GL_BLEND); qglDisable(GL_BLEND); GLboolean cull = qglIsEnabled(GL_CULL_FACE); qglDisable(GL_CULL_FACE); GLboolean depth = qglIsEnabled(GL_DEPTH_TEST); qglDisable(GL_DEPTH_TEST); GLboolean fog = qglIsEnabled(GL_FOG); qglDisable(GL_FOG); GLboolean lighting = qglIsEnabled(GL_LIGHTING); qglDisable(GL_LIGHTING); GLboolean offset = qglIsEnabled(GL_POLYGON_OFFSET_FILL); qglDisable(GL_POLYGON_OFFSET_FILL); GLboolean scissor = qglIsEnabled(GL_SCISSOR_TEST); qglDisable(GL_SCISSOR_TEST); GLboolean stencil = qglIsEnabled(GL_STENCIL_TEST); qglDisable(GL_STENCIL_TEST); GLboolean texture = qglIsEnabled(GL_TEXTURE_2D); qglEnable(GL_TEXTURE_2D); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); #ifdef _XBOX if(glw_state->isWidescreen) qglOrtho(0, 720, 0, 480, 0, 1); else #endif qglOrtho(0, 640, 0, 480, 0, 1); qglMatrixMode(GL_TEXTURE0); qglLoadIdentity(); qglMatrixMode(GL_TEXTURE1); qglLoadIdentity(); qglActiveTextureARB(GL_TEXTURE0_ARB); qglClientActiveTextureARB(GL_TEXTURE0_ARB); memset(&tess, 0, sizeof(tess)); // Draw the error message qglBeginFrame(); if (!SP_LicenseDone) { // clear the screen if we haven't done the // license yet... qglClearColor(0, 0, 0, 1); qglClear(GL_COLOR_BUFFER_BIT); } float x1, x2, y1, y2; #ifdef _XBOX if(glw_state->isWidescreen) { x1 = 0; x2 = 720; y1 = 0; y2 = 480; } else { #endif x1 = 0; x2 = 640; y1 = 0; y2 = 480; #ifdef _XBOX } #endif y1 += vShift; y2 += vShift; qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0); qglTexCoord2f( 0, 0 ); qglVertex2f(x1, y1); qglTexCoord2f( 1 , 0 ); qglVertex2f(x2, y1); qglTexCoord2f( 0, 1 ); qglVertex2f(x1, y2); qglTexCoord2f( 1, 1 ); qglVertex2f(x2, y2); qglEnd(); qglEndFrame(); qglFlush(); // Restore (most) of the render states we reset if (alpha) qglEnable(GL_ALPHA_TEST); else qglDisable(GL_ALPHA_TEST); if (blend) qglEnable(GL_BLEND); else qglDisable(GL_BLEND); if (cull) qglEnable(GL_CULL_FACE); else qglDisable(GL_CULL_FACE); if (depth) qglEnable(GL_DEPTH_TEST); else qglDisable(GL_DEPTH_TEST); if (fog) qglEnable(GL_FOG); else qglDisable(GL_FOG); if (lighting) qglEnable(GL_LIGHTING); else qglDisable(GL_LIGHTING); if (offset) qglEnable(GL_POLYGON_OFFSET_FILL); else qglDisable(GL_POLYGON_OFFSET_FILL); if (scissor) qglEnable(GL_SCISSOR_TEST); else qglDisable(GL_SCISSOR_TEST); if (stencil) qglEnable(GL_STENCIL_TEST); else qglDisable(GL_STENCIL_TEST); if (texture) qglEnable(GL_TEXTURE_2D); else qglDisable(GL_TEXTURE_2D); // Kill the texture qglDeleteTextures(1, &texid); }
void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { swapBuffersCommand_t *cmd; float x; float y; float w; float h; GLuint texID; static int b = 0; if ( !tr.registered ) { return; } cmd = R_GetCommandBuffer( sizeof( *cmd ) ); if ( !cmd ) { return; } cmd->commandId = RC_SWAP_BUFFERS; R_IssueRenderCommands( qtrue ); //*** Rift post processing if (vr_warpingShader->integer) { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); if (!backEnd.projection2D) { RB_SetGL2D(); } glViewport(0, 0, glConfig.vidWidth, glConfig.vidHeight); // Render on the whole framebuffer, complete from the lower left corner to the upper right // Use our shader glUseProgram(glConfig.oculusProgId); glEnable(GL_TEXTURE_2D); { float VPX = 0.0f; float VPY = 0.0f; float VPW = glConfig.vidWidth; // ViewPort Width float VPH = glConfig.vidHeight; SetupShaderDistortion(0, VPX, VPY, VPW, VPH); // Left Eye } // Set our "renderedTexture" sampler to user Texture Unit 0 texID = glGetUniformLocation(glConfig.oculusProgId, "texid"); glUniform1i(texID, 0); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); // if (stereoFrame == STEREO_LEFT) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glConfig.oculusRenderTargetLeft); x = 0.0f; y = 0.0f; w = glConfig.vidWidth; h = glConfig.vidHeight; qglBegin (GL_QUADS); qglTexCoord2f( 0, 1 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 1 ); qglVertex2f( x + w/2, y ); qglTexCoord2f( 1, 0 ); qglVertex2f( x + w/2, y + h ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y + h ); qglEnd(); } //else { { float VPX = 0; float VPY = 0.0f; float VPW = glConfig.vidWidth; // ViewPort Width float VPH = glConfig.vidHeight; SetupShaderDistortion(1, VPX, VPY, VPW, VPH); // Right Eye } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, glConfig.oculusRenderTargetRight); x = glConfig.vidWidth*0.5f; y = 0.0f; w = glConfig.vidWidth; h = glConfig.vidHeight; qglBegin (GL_QUADS); qglTexCoord2f( 0, 1 ); qglVertex2f( x, y ); qglTexCoord2f( 1, 1 ); qglVertex2f( x + w/2, y ); qglTexCoord2f( 1, 0 ); qglVertex2f( x + w/2, y + h ); qglTexCoord2f( 0, 0 ); qglVertex2f( x, y + h ); qglEnd(); } // unbind the GLSL program // this means that from here the OpenGL fixed functionality is used glUseProgram(0); } // use the other buffers next frame, because another CPU // may still be rendering into the current ones R_ToggleSmpFrame(); if ( frontEndMsec ) { *frontEndMsec = tr.frontEndMsec; } tr.frontEndMsec = 0; if ( backEndMsec ) { *backEndMsec = backEnd.pc.msec; } backEnd.pc.msec = 0; }
/* ==================== BuildOptTriangles Generate a new list of triangles from the optEdeges ==================== */ static void BuildOptTriangles( optIsland_t* island ) { optVertex_t* ov = NULL, *second = NULL, *third = NULL, *middle = NULL; optEdge_t* e1 = NULL, *e1Next = NULL, *e2 = NULL, *e2Next = NULL, *check = NULL, *checkNext = NULL; // free them FreeOptTriangles( island ); // clear the vertex emitted flags for( ov = island->verts ; ov ; ov = ov->islandLink ) { ov->emited = false; } // clear the edge triangle links for( check = island->edges ; check ; check = check->islandLink ) { check->frontTri = check->backTri = NULL; } // check all possible triangle made up out of the // edges coming off the vertex for( ov = island->verts ; ov ; ov = ov->islandLink ) { if( !ov->edges ) { continue; } #if 0 if( dmapGlobals.drawflag && ov == ( optVertex_t* )0x1845a60 ) { for( e1 = ov->edges ; e1 ; e1 = e1Next ) { qglBegin( GL_LINES ); qglColor3f( 0, 1, 0 ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); if( e1->v1 == ov ) { e1Next = e1->v1link; } else if( e1->v2 == ov ) { e1Next = e1->v2link; } } } #endif for( e1 = ov->edges ; e1 ; e1 = e1Next ) { if( e1->v1 == ov ) { second = e1->v2; e1Next = e1->v1link; } else if( e1->v2 == ov ) { second = e1->v1; e1Next = e1->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } // if the vertex has already been used, it can't be used again if( second->emited ) { continue; } for( e2 = ov->edges ; e2 ; e2 = e2Next ) { if( e2->v1 == ov ) { third = e2->v2; e2Next = e2->v1link; } else if( e2->v2 == ov ) { third = e2->v1; e2Next = e2->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if( e2 == e1 ) { continue; } // if the vertex has already been used, it can't be used again if( third->emited ) { continue; } // if the triangle is backwards or degenerate, don't use it if( !IsTriangleValid( ov, second, third ) ) { continue; } // see if any other edge bisects these two, which means // this triangle shouldn't be used for( check = ov->edges ; check ; check = checkNext ) { if( check->v1 == ov ) { middle = check->v2; checkNext = check->v1link; } else if( check->v2 == ov ) { middle = check->v1; checkNext = check->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } if( check == e1 || check == e2 ) { continue; } if( IsTriangleValid( ov, second, middle ) && IsTriangleValid( ov, middle, third ) ) { break; // should use the subdivided ones } } if( check ) { continue; // don't use it } // the triangle is valid CreateOptTri( ov, e1, e2, island ); } } // later vertexes will not emit triangles that use an // edge that this vert has already used ov->emited = true; } }
/* ============== CZWnd::Z_Draw ============== */ void CZWnd::Z_Draw( void ) { brush_t *brush; float w, h; float top, bottom; idVec3 org_top, org_bottom, dir_up, dir_down; int xCam = z.width / 3 / z.scale; // sikk - Keep brush widths proportional to window if ( !active_brushes.next ) { return; // not valid yet } // clear qglViewport( 0, 0, z.width, z.height ); qglScissor( 0, 0, z.width, z.height ); qglClearColor( g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2], 0 ); /* * GL Bug £ * When not using hw acceleration, gl will fault if we clear the depth buffer bit * on the first pass. The hack fix is to set the GL_DEPTH_BUFFER_BIT only after * Z_Draw() has been called once. Yeah, right. £ * qglClear(glbitClear); */ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // // glbitClear |= GL_DEPTH_BUFFER_BIT; // qglClear(GL_DEPTH_BUFFER_BIT); // qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); w = z.width / 2 / z.scale; h = z.height / 2 / z.scale; qglOrtho( -w, w, z.origin[2] - h, z.origin[2] + h, -8, 8 ); globalImages->BindNull(); qglDisable( GL_DEPTH_TEST ); qglDisable( GL_BLEND ); // now draw the grid Z_DrawGrid(); // draw stuff qglDisable( GL_CULL_FACE ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); globalImages->BindNull(); // draw filled interiors and edges dir_up[0] = 0; dir_up[1] = 0; dir_up[2] = 1; dir_down[0] = 0; dir_down[1] = 0; dir_down[2] = -1; VectorCopy( z.origin, org_top ); org_top[2] = 4096; VectorCopy( z.origin, org_bottom ); org_bottom[2] = -4096; for ( brush = active_brushes.next; brush != &active_brushes; brush = brush->next ) { if ( brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1] ) { continue; } if ( !Brush_Ray( org_top, dir_down, brush, &top ) ) { continue; } top = org_top[2] - top; if ( !Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) { continue; } bottom = org_bottom[2] + bottom; //q = declManager->FindMaterial( brush->brush_faces->texdef.name ); qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z ); qglBegin( GL_QUADS ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); } // now draw selected brushes for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next ) { if ( !( brush->mins[0] >= z.origin[0] || brush->maxs[0] <= z.origin[0] || brush->mins[1] >= z.origin[1] || brush->maxs[1] <= z.origin[1] ) ) { if ( Brush_Ray( org_top, dir_down, brush, &top ) ) { top = org_top[2] - top; if ( Brush_Ray( org_bottom, dir_up, brush, &bottom ) ) { bottom = org_bottom[2] + bottom; //q = declManager->FindMaterial( brush->brush_faces->texdef.name ); qglColor3f( brush->owner->eclass->color.x, brush->owner->eclass->color.y, brush->owner->eclass->color.z ); qglBegin( GL_QUADS ); qglVertex2f( -xCam, bottom ); qglVertex2f( xCam, bottom ); qglVertex2f( xCam, top ); qglVertex2f( -xCam, top ); qglEnd(); } } } qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() ); qglBegin( GL_LINE_LOOP ); qglVertex2f( -xCam, brush->mins[2] ); qglVertex2f( xCam, brush->mins[2] ); qglVertex2f( xCam, brush->maxs[2] ); qglVertex2f( -xCam, brush->maxs[2] ); qglEnd(); } Z_DrawCameraIcon(); Z_DrawZClip(); qglFinish(); QE_CheckOpenGLForErrors(); }
void CCamWnd::Cam_Draw() { brush_t *brush; face_t *face; float screenaspect; float yfov; double start, end; int i; /* FILE *f = fopen("g:/nardo/raduffy/editorhack.dat", "w"); if (f != NULL) { fwrite(&m_Camera.origin[0], sizeof(float), 1, f); fwrite(&m_Camera.origin[1], sizeof(float), 1, f); fwrite(&m_Camera.origin[2], sizeof(float), 1, f); fwrite(&m_Camera.angles[PITCH], sizeof(float), 1, f); fwrite(&m_Camera.angles[YAW], sizeof(float), 1, f); fclose(f); } */ if (!active_brushes.next) return; // not valid yet if (m_Camera.timing) start = Sys_DoubleTime (); // // clear // QE_CheckOpenGLForErrors(); qglViewport(0, 0, m_Camera.width, m_Camera.height); qglScissor(0, 0, m_Camera.width, m_Camera.height); qglClearColor (g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], 0); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // // set up viewpoint // vec5_t lightPos; if (g_PrefsDlg.m_bGLLighting) { qglEnable(GL_LIGHTING); //qglEnable(GL_LIGHT0); lightPos[0] = lightPos[1] = lightPos[2] = 3.5; lightPos[3] = 1.0; qglLightModelfv(GL_LIGHT_MODEL_AMBIENT, lightPos); //qglLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); //lightPos[0] = lightPos[1] = lightPos[2] = 3.5; //qglLightfv(GL_LIGHT0, GL_AMBIENT, lightPos); } else { qglDisable(GL_LIGHTING); } qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); screenaspect = (float)m_Camera.width / m_Camera.height; yfov = 2*atan((float)m_Camera.height / m_Camera.width)*180/Q_PI; qgluPerspective (yfov, screenaspect, 2, 8192); qglRotatef (-90, 1, 0, 0); // put Z going up qglRotatef (90, 0, 0, 1); // put Z going up qglRotatef (m_Camera.angles[0], 0, 1, 0); qglRotatef (-m_Camera.angles[1], 0, 0, 1); qglTranslatef (-m_Camera.origin[0], -m_Camera.origin[1], -m_Camera.origin[2]); Cam_BuildMatrix (); //if (m_Camera.draw_mode == cd_light) //{ // if (g_PrefsDlg.m_bGLLighting) // { // VectorCopy(m_Camera.origin, lightPos); // lightPos[3] = 1; // qglLightfv(GL_LIGHT0, GL_POSITION, lightPos); // } //} InitCull (); // // draw stuff // GLfloat lAmbient[] = {1.0, 1.0, 1.0, 1.0}; switch (m_Camera.draw_mode) { case cd_wire: qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglDisable(GL_TEXTURE_2D); qglDisable(GL_TEXTURE_1D); qglDisable(GL_BLEND); qglDisable(GL_DEPTH_TEST); qglColor3f(1.0, 1.0, 1.0); // qglEnable (GL_LINE_SMOOTH); break; case cd_solid: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglDisable(GL_TEXTURE_2D); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglDepthFunc (GL_LEQUAL); break; case cd_texture: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglEnable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglDisable(GL_BLEND); qglEnable(GL_DEPTH_TEST); qglDepthFunc (GL_LEQUAL); break; case cd_blend: qglCullFace(GL_FRONT); qglEnable(GL_CULL_FACE); qglShadeModel (GL_FLAT); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglEnable(GL_TEXTURE_2D); qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); qglDisable(GL_DEPTH_TEST); qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; } qglMatrixMode(GL_TEXTURE); m_nNumTransBrushes = 0; for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) { //DrawLightRadius(brush); if (CullBrush (brush)) continue; if (FilterBrush (brush)) continue; if ((brush->brush_faces->texdef.flags & (SURF_TRANS33 | SURF_TRANS66)) || (brush->brush_faces->d_texture->bFromShader && brush->brush_faces->d_texture->fTrans != 1.0)) { m_TransBrushes [ m_nNumTransBrushes++ ] = brush; } else { //-- if (brush->patchBrush) //-- m_TransBrushes [ m_nNumTransBrushes++ ] = brush; //-- else Brush_Draw(brush); } } if (g_PrefsDlg.m_bGLLighting) { qglDisable (GL_LIGHTING); } // //qglDepthMask ( 0 ); // Don't write to depth buffer qglEnable ( GL_BLEND ); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); for ( i = 0; i < m_nNumTransBrushes; i++ ) Brush_Draw (m_TransBrushes[i]); //qglDepthMask ( 1 ); // Ok, write now qglMatrixMode(GL_PROJECTION); // // now draw selected brushes // if (g_PrefsDlg.m_bGLLighting) { qglEnable (GL_LIGHTING); } qglTranslatef (g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); qglMatrixMode(GL_TEXTURE); brush_t* pList = (g_bClipMode && g_pSplitList) ? g_pSplitList : &selected_brushes; // draw normally for (brush = pList->next ; brush != pList ; brush=brush->next) { //DrawLightRadius(brush); //if (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) // continue; Brush_Draw(brush); } // blend on top qglMatrixMode(GL_PROJECTION); qglDisable (GL_LIGHTING); qglColor4f(1.0, 0.0, 0.0, 0.3); qglEnable (GL_BLEND); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglDisable (GL_TEXTURE_2D); for (brush = pList->next ; brush != pList ; brush=brush->next) { if ( (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) || (brush->terrainBrush && g_qeglobals.d_select_mode == sel_terrainpoint) ) continue; for (face=brush->brush_faces ; face ; face=face->next) Face_Draw( face ); } int nCount = g_ptrSelectedFaces.GetSize(); if (nCount > 0) { for (int i = 0; i < nCount; i++) { face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i)); Face_Draw(selFace); } } // non-zbuffered outline qglDisable (GL_BLEND); qglDisable (GL_DEPTH_TEST); qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); qglColor3f (1, 1, 1); for (brush = pList->next ; brush != pList ; brush=brush->next) { if (g_qeglobals.dontDrawSelectedOutlines || (brush->patchBrush && g_qeglobals.d_select_mode == sel_curvepoint) || (brush->terrainBrush && g_qeglobals.d_select_mode == sel_terrainpoint)) continue; for (face=brush->brush_faces ; face ; face=face->next) Face_Draw( face ); } // edge / vertex flags if (g_qeglobals.d_select_mode == sel_vertex) { qglPointSize (4); qglColor3f (0,1,0); qglBegin (GL_POINTS); for (i=0 ; i<g_qeglobals.d_numpoints ; i++) qglVertex3fv (g_qeglobals.d_points[i]); qglEnd (); qglPointSize (1); } else if (g_qeglobals.d_select_mode == sel_edge) { float *v1, *v2; qglPointSize (4); qglColor3f (0,0,1); qglBegin (GL_POINTS); for (i=0 ; i<g_qeglobals.d_numedges ; i++) { v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1]; v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2]; qglVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5); } qglEnd (); qglPointSize (1); } g_splineList->draw(static_cast<qboolean>(g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint)); if (g_qeglobals.selectObject && (g_qeglobals.d_select_mode == sel_addpoint || g_qeglobals.d_select_mode == sel_editpoint)) { g_qeglobals.selectObject->drawSelection(); } // // draw pointfile // qglEnable(GL_DEPTH_TEST); DrawPathLines (); if (g_qeglobals.d_pointfile_display_list) { Pointfile_Draw(); // glCallList (g_qeglobals.d_pointfile_display_list); } // bind back to the default texture so that we don't have problems // elsewhere using/modifying texture maps between contexts qglBindTexture( GL_TEXTURE_2D, 0 ); #if 0 // area selection hack if (g_qeglobals.d_select_mode == sel_area) { qglEnable (GL_BLEND); qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglColor4f(0.0, 0.0, 1.0, 0.25); qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); qglRectfv(g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR); qglDisable (GL_BLEND); } #endif qglFinish(); QE_CheckOpenGLForErrors(); // Sys_EndWait(); if (m_Camera.timing) { end = Sys_DoubleTime (); Sys_Printf ("Camera: %i ms\n", (int)(1000*(end-start))); } }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones) { int i; int *boneRefs; float torsoWeight; // if the entity has changed since the last time the bones were built, reset them if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t))) { // different, cached bones are not valid memset(validBones, 0, header->numBones); lastBoneEntity = *refent; // (SA) also reset these counter statics //----(SA) print stats for the complete model (not per-surface) if (r_bonesDebug->integer == 4 && totalrt) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, totalrv, totalv, totalrt, totalt, ( float )(100.0 * totalrt) / (float) totalt); } totalrv = totalrt = totalv = totalt = 0; } memset(newBones, 0, header->numBones); if (refent->oldframe == refent->frame) { backlerp = 0; frontlerp = 1; } else { backlerp = refent->backlerp; frontlerp = 1.0f - backlerp; } if (refent->oldTorsoFrame == refent->torsoFrame) { torsoBacklerp = 0; torsoFrontlerp = 1; } else { torsoBacklerp = refent->torsoBacklerp; torsoFrontlerp = 1.0f - torsoBacklerp; } frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t)); frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->frame * frameSize); torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->torsoFrame * frameSize); oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldframe * frameSize); oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldTorsoFrame * frameSize); // lerp all the needed bones (torsoParent is always the first bone in the list) cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones); boneRefs = boneList; // Matrix3Transpose(refent->torsoAxis, torsoAxis); #ifdef HIGH_PRECISION_BONES if (qtrue) { #else if (!backlerp && !torsoBacklerp) { #endif for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBone(header, refent, boneInfo[*boneRefs].parent); } R_CalcBone(header, refent, *boneRefs); } } else // interpolated { cOldBoneList = oldFrame->bones; cOldBoneListTorso = oldTorsoFrame->bones; for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent); } R_CalcBoneLerp(header, refent, *boneRefs); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for (i = 0; i < numBones; i++, boneRefs++) { thisBoneInfo = &boneInfo[*boneRefs]; bonePtr = &bones[*boneRefs]; // add torso rotation if (thisBoneInfo->torsoWeight > 0) { if (!newBones[*boneRefs]) { // just copy it back from the previous calc bones[*boneRefs] = oldBones[*boneRefs]; continue; } if (!(thisBoneInfo->flags & BONEFLAG_TAG)) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract(bonePtr->translation, torsoParentOffset, t); Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if (torsoWeight != thisBoneInfo->torsoWeight) { Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation); } else // tag's require special handling { // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]); LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]); LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]); memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis)); // rotate the translation around the torsoParent VectorSubtract(bonePtr->translation, torsoParentOffset, t); LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation); VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation); } } } // backup the final bones memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones); } #ifdef DBG_PROFILE_BONES #define DBG_SHOWTIME Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt; #else #define DBG_SHOWTIME ; #endif /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim(mdsSurface_t *surface) { int j, k; refEntity_t *refent; int *boneList; mdsHeader_t *header; #ifdef DBG_PROFILE_BONES int di = 0, dt, ldt; dt = ri.Milliseconds(); ldt = dt; #endif refent = &backEnd.currentEntity->e; boneList = ( int * )((byte *)surface + surface->ofsBoneReferences); header = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader); R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences); DBG_SHOWTIME // calculate LOD // TODO: lerp the radius and origin VectorAdd(refent->origin, frame->localOrigin, vec); lodRadius = frame->radius; lodScale = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale); //DBG_SHOWTIME // modification to allow dead skeletal bodies to go below minlod (experiment) if (refent->reFlags & REFLAG_DEAD_LOD) { if (lodScale < 0.35) // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally. worked for the blackguard/infantry as a test though) { lodScale = 0.35; } render_count = ROUND_INT((float) surface->numVerts * lodScale); } else { render_count = ROUND_INT((float) surface->numVerts * lodScale); if (render_count < surface->minLod) { if (!(refent->reFlags & REFLAG_DEAD_LOD)) { render_count = surface->minLod; } } } if (render_count > surface->numVerts) { render_count = surface->numVerts; } RB_CheckOverflow(render_count, surface->numTriangles * 3); //DBG_SHOWTIME // setup triangle list //DBG_SHOWTIME collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap); triangles = ( int * )((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //DBG_SHOWTIME if (render_count == surface->numVerts) { for (j = 0; j < indexes; j++) { pIndexes[j] = triangles[j] + baseVertex; } tess.numIndexes += indexes; } else { int *collapseEnd; pCollapse = collapse; for (j = 0; j < render_count; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &collapse_map[render_count]; for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++) { *pCollapse = collapse[*pCollapseMap]; } for (j = 0 ; j < indexes ; j += 3) { p0 = collapse[*(triangles++)]; p1 = collapse[*(triangles++)]; p2 = collapse[*(triangles++)]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (p0 == p1 || p1 == p2 || p2 == p0) { continue; } *(pIndexes++) = baseVertex + p0; *(pIndexes++) = baseVertex + p1; *(pIndexes++) = baseVertex + p2; tess.numIndexes += 3; } baseIndex = tess.numIndexes; } //DBG_SHOWTIME // deform the vertexes by the lerped bones numVerts = surface->numVerts; v = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts); tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4) { mdsWeight_t *w; VectorClear(tempVert); w = v->weights; for (k = 0 ; k < v->numWeights ; k++, w++) { bone = &bones[w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert); } LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal); tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0]; tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } DBG_SHOWTIME if (r_bonesDebug->integer) { if (r_bonesDebug->integer < 3) { int i; // DEBUG: show the bones as a stick figure with axis at each bone boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences); for (i = 0; i < surface->numBoneReferences; i++, boneRefs++) { bonePtr = &bones[*boneRefs]; GL_Bind(tr.whiteImage); qglLineWidth(1); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); for (j = 0; j < 3; j++) { VectorClear(vec); vec[j] = 1; qglColor3fv(vec); qglVertex3fv(bonePtr->translation); VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec); qglVertex3fv(vec); } qglEnd(); #endif // 0 // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); #endif } qglLineWidth(1); } } if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4) { int render_indexes = (tess.numIndexes - oldIndexes); // show mesh edges tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); GL_Bind(tr.whiteImage); qglLineWidth(1); #if 0 // TODO: OpenGL ES renderer qglBegin(GL_LINES); qglColor3f(.0, .0, .8); pIndexes = &tess.indexes[oldIndexes]; for (j = 0; j < render_indexes / 3; j++, pIndexes += 3) { qglVertex3fv(tempVert + 4 * pIndexes[0]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[0]); } qglEnd(); #endif // 0 // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
/* ================ RB_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky( void ) { if ( g_bRenderGlowingObjects ) return; if ( r_fastsky->integer ) { return; } if (skyboxportal && !(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL)) { return; } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons( &tess ); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { #ifdef _XBOX qglDepthRange( 0.99, 1.0 ); #else qglDepthRange( 1.0, 1.0 ); #endif } // draw the outer skybox if ( tess.shader->sky->outerbox[0] && tess.shader->sky->outerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix (); GL_State( 0 ); qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); DrawSkyBox( tess.shader ); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData( &tess ); if (tess.numIndexes && tess.numVertexes) { RB_StageIteratorGeneric(); } // draw the inner skybox // back to normal depth range qglDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }
/* ================ rvGEWorkspace::Render Renders the workspace to the given DC ================ */ void rvGEWorkspace::Render ( HDC hdc ) { int front; int back; float scale; scale = g_ZoomScales[mZoom]; // Switch GL contexts to our dc if (!qwglMakeCurrent( hdc, win32.hGLRC )) { common->Printf("ERROR: wglMakeCurrent failed.. Error:%i\n", qglGetError()); common->Printf("Please restart Q3Radiant if the Map view is not working\n"); return; } // Prepare the view and clear it GL_State( GLS_DEFAULT ); qglViewport(0, 0, mWindowWidth, mWindowHeight ); qglScissor(0, 0, mWindowWidth, mWindowHeight ); qglClearColor ( 0.75f, 0.75f, 0.75f, 0 ); qglDisable(GL_DEPTH_TEST); qglDisable(GL_CULL_FACE); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Render the workspace below glMatrixMode(GL_PROJECTION); glLoadIdentity(); qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); qglColor3f ( mApplication->GetOptions().GetWorkspaceColor()[0], mApplication->GetOptions().GetWorkspaceColor()[1], mApplication->GetOptions().GetWorkspaceColor()[2] ); qglBegin ( GL_QUADS ); qglVertex2f ( mRect.x, mRect.y ); qglVertex2f ( mRect.x + mRect.w, mRect.y ); qglVertex2f ( mRect.x + mRect.w, mRect.y + mRect.h ); qglVertex2f ( mRect.x, mRect.y + mRect.h ); qglEnd ( ); // Prepare the renderSystem view to draw the GUI in viewDef_t viewDef; memset ( &viewDef, 0, sizeof(viewDef) ); tr.viewDef = &viewDef; tr.viewDef->renderView.x = mRect.x; tr.viewDef->renderView.y = mWindowHeight - mRect.y - mRect.h; tr.viewDef->renderView.width = mRect.w; tr.viewDef->renderView.height = mRect.h; tr.viewDef->scissor.x1 = 0; tr.viewDef->scissor.y1 = 0; tr.viewDef->scissor.x2 = mRect.w; tr.viewDef->scissor.y2 = mRect.h; tr.viewDef->isEditor = true; renderSystem->BeginFrame(mWindowWidth, mWindowHeight ); // Draw the gui mInterface->Redraw ( 0 ); // eventLoop->Milliseconds() ); // We are done using the renderSystem now renderSystem->EndFrame( &front, &back ); if ( mApplication->GetActiveWorkspace ( ) == this ) { mApplication->GetStatusBar().SetTriangles ( backEnd.pc.c_drawIndexes/3 ); } // Prepare the viewport for drawing selections, etc. GL_State( GLS_DEFAULT ); qglDisable( GL_TEXTURE_CUBE_MAP_EXT ); // qglDisable(GL_BLEND); qglDisable(GL_CULL_FACE); qglViewport(0, 0, mWindowWidth, mWindowHeight ); qglScissor(0, 0, mWindowWidth, mWindowHeight ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); qglOrtho(0,mWindowWidth, mWindowHeight, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); RenderGrid ( ); mSelections.Render ( ); qglFinish ( ); qwglSwapBuffers(hdc); qglEnable( GL_TEXTURE_CUBE_MAP_EXT ); qglEnable( GL_CULL_FACE); }
/* ============== RenderBumpTriangles ============== */ static void RenderBumpTriangles( srfTriangles_t *lowMesh, renderBump_t *rb ) { int i, j; RB_SetGL2D(); qglDisable( GL_CULL_FACE ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, 1, 1, 0, -1, 1 ); qglDisable( GL_BLEND ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); qglDisable( GL_DEPTH_TEST ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglColor3f( 1, 1, 1 ); // create smoothed normals for the surface, which might be // different than the normals at the vertexes if the // surface uses unsmoothedNormals, which only takes the // normal from a single triangle. We need properly smoothed // normals to make sure that the traces always go off normal // to the true surface. idVec3 *lowMeshNormals = (idVec3 *)Mem_ClearedAlloc( lowMesh->numVerts * sizeof( *lowMeshNormals ) ); R_DeriveFacePlanes( lowMesh ); R_CreateSilIndexes( lowMesh ); // recreate, merging the mirrored verts back together const idPlane *planes = lowMesh->facePlanes; for ( i = 0 ; i < lowMesh->numIndexes ; i += 3, planes++ ) { for ( j = 0 ; j < 3 ; j++ ) { int index; index = lowMesh->silIndexes[i+j]; lowMeshNormals[index] += (*planes).Normal(); } } // normalize and replicate from silIndexes to all indexes for ( i = 0 ; i < lowMesh->numIndexes ; i++ ) { lowMeshNormals[lowMesh->indexes[i]] = lowMeshNormals[lowMesh->silIndexes[i]]; lowMeshNormals[lowMesh->indexes[i]].Normalize(); } // rasterize each low poly face for ( j = 0 ; j < lowMesh->numIndexes ; j+=3 ) { // pump the event loop so the window can be dragged around Sys_GenerateEvents(); RasterizeTriangle( lowMesh, lowMeshNormals, j/3, rb ); qglClearColor(1,0,0,1); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglRasterPos2f( 0, 1 ); qglPixelZoom( glConfig.vidWidth / (float)rb->width, glConfig.vidHeight / (float)rb->height ); qglDrawPixels( rb->width, rb->height, GL_RGBA, GL_UNSIGNED_BYTE, rb->localPic ); qglPixelZoom( 1, 1 ); qglFlush(); GLimp_SwapBuffers(); } Mem_Free( lowMeshNormals ); }
void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) { int i; int w; int h; int x; int y; //int n; //float x1; //float y1; float scale_x; float scale_y; //vec3_t pSelectedPoints[ MAX_TERRA_POINTS ]; //int nIndex; terravert_t a0; terravert_t a1; terravert_t a2; terravert_t b0; terravert_t b1; terravert_t b2; terrainVert_t *vert; qtexture_t *texture; h = pm->height - 1; w = pm->width - 1; scale_x = pm->scale_x; scale_y = pm->scale_y; qglShadeModel (GL_SMOOTH); if ( bShade ) { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } else { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } qglPushAttrib( GL_CURRENT_BIT ); bool bDisabledLighting = qglIsEnabled( GL_LIGHTING ); if ( bDisabledLighting ) { qglDisable( GL_LIGHTING ); } #if 0 terrainVert_t *currentrow; terrainVert_t *nextrow; float x2; float y2; // Draw normals qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINES ); y2 = pm->origin[ 1 ]; nextrow = pm->heightmap; for( y = 0; y < h; y++ ) { y1 = y2; y2 += scale_y; x2 = pm->origin[ 0 ]; currentrow = nextrow; nextrow = currentrow + pm->width; for( x = 0; x < w; x++ ) { x1 = x2; x2 += scale_x; // normals qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height ); qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height ); qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f ); qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height ); qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height ); qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f ); } } qglEnd (); qglEnable( GL_TEXTURE_2D ); #endif #if 0 if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) { qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); nIndex = 0; qglColor4f( 1, 0, 1, 1 ); y1 = pm->origin[ 1 ]; for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) { x1 = pm->origin[ 0 ]; for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) { // FIXME: need to not do loop lookups inside here n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] ); if ( n >= 0 ) { VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] ); nIndex++; } else { qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height ); } } } qglEnd(); qglEnable( GL_TEXTURE_2D ); if ( nIndex > 0 ) { qglBegin( GL_POINTS ); qglColor4f( 0, 0, 1, 1 ); while( nIndex-- > 0 ) { qglVertex3fv( pSelectedPoints[ nIndex ] ); } qglEnd(); } } #endif if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) { #if 0 qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); qglColor4f( 1, 0, 1, 1 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); #endif brush_t *pb; terrainMesh_t *pm; pm = NULL; for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) { if ( pb->terrainBrush ) { pm = pb->pTerrain; break; } } if ( pm ) { qglDisable( GL_TEXTURE_2D ); qglBegin( GL_TRIANGLES ); qglEnable( GL_BLEND ); qglColor4f( 0.25, 0.5, 1, 0.35 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { terravert_t a0; terravert_t a1; terravert_t a2; qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); } qglEnd(); qglDisable( GL_BLEND ); qglEnable( GL_TEXTURE_2D ); } } }
/* ============== RenderBumpFlat_f ============== */ void RenderBumpFlat_f( const idCmdArgs &args ) { int width, height; idStr source; int i; idBounds bounds; srfTriangles_t *mesh; float boundsScale; // update the screen as we print common->SetRefreshOnPrint( true ); width = height = 256; boundsScale = 0; // check options for ( i = 1 ; i < args.Argc() - 1; i++ ) { const char *s; s = args.Argv( i ); if ( s[0] == '-' ) { i++; s = args.Argv( i ); } if ( !idStr::Icmp( s, "size" ) ) { if ( i + 2 >= args.Argc() ) { i = args.Argc(); break; } width = atoi( args.Argv( i + 1 ) ); height = atoi( args.Argv( i + 2 ) ); i += 2; } else { common->Printf( "WARNING: Unknown option \"%s\"\n", s ); break; } } if ( i != ( args.Argc() - 1 ) ) { common->Error( "usage: renderBumpFlat [-size width height] asefile" ); } common->Printf( "Final image size: %i, %i\n", width, height ); // load the source in "fastload" mode, because we don't // need tangent and shadow information source = args.Argv( i ); idRenderModel *highPolyModel = renderModelManager->AllocModel(); highPolyModel->PartialInitFromFile( source ); if ( highPolyModel->IsDefaultModel() ) { common->Error( "failed to load %s", source.c_str() ); } // combine the high poly model into a single polyset if ( highPolyModel->NumSurfaces() != 1 ) { highPolyModel = CombineModelSurfaces( highPolyModel ); } // create normals if not present in file const modelSurface_t *surf = highPolyModel->Surface( 0 ); mesh = surf->geometry; // bound the entire file R_BoundTriSurf( mesh ); bounds = mesh->bounds; SaveWindow(); ResizeWindow( width, height ); // for small images, the viewport may be less than the minimum window qglViewport( 0, 0, width, height ); qglEnable( GL_CULL_FACE ); qglCullFace( GL_FRONT ); qglDisable( GL_STENCIL_TEST ); qglDisable( GL_SCISSOR_TEST ); qglDisable( GL_ALPHA_TEST ); qglDisable( GL_BLEND ); qglEnable( GL_DEPTH_TEST ); qglDisable( GL_TEXTURE_2D ); qglDepthMask( GL_TRUE ); qglDepthFunc( GL_LEQUAL ); qglColor3f( 1, 1, 1 ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( bounds[0][0], bounds[1][0], bounds[0][2], bounds[1][2], -( bounds[0][1] - 1 ), -( bounds[1][1] + 1 ) ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); // flat maps are automatically anti-aliased idStr filename; int j, k, c; byte *buffer; int *sumBuffer, *colorSumBuffer; bool flat; int sample; sumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 ); memset( sumBuffer, 0, width * height * 4 * 4 ); buffer = (byte *)Mem_Alloc( width * height * 4 ); colorSumBuffer = (int *)Mem_Alloc( width * height * 4 * 4 ); memset( sumBuffer, 0, width * height * 4 * 4 ); flat = false; //flat = true; for ( sample = 0 ; sample < 16 ; sample++ ) { float xOff, yOff; xOff = ( ( sample & 3 ) / 4.0 ) * ( bounds[1][0] - bounds[0][0] ) / width; yOff = ( ( sample / 4 ) / 4.0 ) * ( bounds[1][2] - bounds[0][2] ) / height; for ( int colorPass = 0 ; colorPass < 2 ; colorPass++ ) { qglClearColor(0.5,0.5,0.5,0); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglBegin( GL_TRIANGLES ); for ( i = 0 ; i < highPolyModel->NumSurfaces() ; i++ ) { const modelSurface_t *surf = highPolyModel->Surface( i ); mesh = surf->geometry; if ( colorPass ) { // just render the surface color for artist visualization for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) { for ( k = 0 ; k < 3 ; k++ ) { int v; float *a; v = mesh->indexes[j+k]; qglColor3ubv( mesh->verts[v].color ); a = mesh->verts[v].xyz.ToFloatPtr(); qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] ); } } } else { // render as normal map // we can either flat shade from the plane, // or smooth shade from the vertex normals for ( j = 0 ; j < mesh->numIndexes ; j+=3 ) { if ( flat ) { idPlane plane; idVec3 *a, *b, *c; int v1, v2, v3; v1 = mesh->indexes[j+0]; v2 = mesh->indexes[j+1]; v3 = mesh->indexes[j+2]; a = &mesh->verts[ v1 ].xyz; b = &mesh->verts[ v2 ].xyz; c = &mesh->verts[ v3 ].xyz; plane.FromPoints( *a, *b, *c ); // NULLNORMAL is used by the artists to force an area to reflect no // light at all if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) { qglColor3f( 0.5, 0.5, 0.5 ); } else { qglColor3f( 0.5 + 0.5*plane[0], 0.5 - 0.5*plane[2], 0.5 - 0.5*plane[1] ); } qglVertex3f( (*a)[0] + xOff, (*a)[2] + yOff, (*a)[1] ); qglVertex3f( (*b)[0] + xOff, (*b)[2] + yOff, (*b)[1] ); qglVertex3f( (*c)[0] + xOff, (*c)[2] + yOff, (*c)[1] ); } else { for ( k = 0 ; k < 3 ; k++ ) { int v; float *n; float *a; v = mesh->indexes[j+k]; n = mesh->verts[v].normal.ToFloatPtr(); // NULLNORMAL is used by the artists to force an area to reflect no // light at all if ( surf->shader->GetSurfaceFlags() & SURF_NULLNORMAL ) { qglColor3f( 0.5, 0.5, 0.5 ); } else { // we are going to flip the normal Z direction qglColor3f( 0.5 + 0.5*n[0], 0.5 - 0.5*n[2], 0.5 - 0.5*n[1] ); } a = mesh->verts[v].xyz.ToFloatPtr(); qglVertex3f( a[0] + xOff, a[2] + yOff, a[1] ); } } } } } qglEnd(); qglFlush(); GLimp_SwapBuffers(); qglReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); if ( colorPass ) { // add to the sum buffer for ( i = 0 ; i < c ; i++ ) { colorSumBuffer[i*4+0] += buffer[i*4+0]; colorSumBuffer[i*4+1] += buffer[i*4+1]; colorSumBuffer[i*4+2] += buffer[i*4+2]; colorSumBuffer[i*4+3] += buffer[i*4+3]; } } else { // normalize c = width * height; for ( i = 0 ; i < c ; i++ ) { idVec3 v; v[0] = ( buffer[i*4+0] - 128 ) / 127.0; v[1] = ( buffer[i*4+1] - 128 ) / 127.0; v[2] = ( buffer[i*4+2] - 128 ) / 127.0; v.Normalize(); buffer[i*4+0] = 128 + 127 * v[0]; buffer[i*4+1] = 128 + 127 * v[1]; buffer[i*4+2] = 128 + 127 * v[2]; } // outline into non-drawn areas for ( i = 0 ; i < 8 ; i++ ) { OutlineNormalMap( buffer, width, height, 128, 128, 128 ); } // add to the sum buffer for ( i = 0 ; i < c ; i++ ) { sumBuffer[i*4+0] += buffer[i*4+0]; sumBuffer[i*4+1] += buffer[i*4+1]; sumBuffer[i*4+2] += buffer[i*4+2]; sumBuffer[i*4+3] += buffer[i*4+3]; } } } } c = width * height; // save out the color map for ( i = 0 ; i < c ; i++ ) { buffer[i*4+0] = colorSumBuffer[i*4+0] / 16; buffer[i*4+1] = colorSumBuffer[i*4+1] / 16; buffer[i*4+2] = colorSumBuffer[i*4+2] / 16; buffer[i*4+3] = colorSumBuffer[i*4+3] / 16; } filename = source; filename.StripFileExtension(); filename.Append( "_color.tga" ); R_VerticalFlip( buffer, width, height ); R_WriteTGA( filename, buffer, width, height ); // save out the local map // scale the sum buffer back down to the sample buffer // we allow this to denormalize for ( i = 0 ; i < c ; i++ ) { buffer[i*4+0] = sumBuffer[i*4+0] / 16; buffer[i*4+1] = sumBuffer[i*4+1] / 16; buffer[i*4+2] = sumBuffer[i*4+2] / 16; buffer[i*4+3] = sumBuffer[i*4+3] / 16; } filename = source; filename.StripFileExtension(); filename.Append( "_local.tga" ); common->Printf( "writing %s (%i,%i)\n", filename.c_str(), width, height ); R_VerticalFlip( buffer, width, height ); R_WriteTGA( filename, buffer, width, height ); // free the model renderModelManager->FreeModel( highPolyModel ); // free our work buffer Mem_Free( buffer ); Mem_Free( sumBuffer ); Mem_Free( colorSumBuffer ); RestoreWindow(); // stop updating the screen as we print common->SetRefreshOnPrint( false ); common->Error( "Completed." ); }
static void RemoveIfColinear( optVertex_t* ov, optIsland_t* island ) { optEdge_t* e, *e1, *e2; optVertex_t* v1 = NULL, *v2 = NULL, *v3 = NULL; idVec3 dir1, dir2; float len, dist; idVec3 point; idVec3 offset; float off; v2 = ov; // we must find exactly two edges before testing for colinear e1 = NULL; e2 = NULL; for( e = ov->edges ; e ; ) { if( !e1 ) { e1 = e; } else if( !e2 ) { e2 = e; } else { return; // can't remove a vertex with three edges } if( e->v1 == v2 ) { e = e->v1link; } else if( e->v2 == v2 ) { e = e->v2link; } else { common->Error( "RemoveIfColinear: mislinked edge" ); } } // can't remove if no edges if( !e1 ) { return; } if( !e2 ) { // this may still happen legally when a tiny triangle is // the only thing in a group common->Printf( "WARNING: vertex with only one edge\n" ); return; } if( e1->v1 == v2 ) { v1 = e1->v2; } else if( e1->v2 == v2 ) { v1 = e1->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); } if( e2->v1 == v2 ) { v3 = e2->v2; } else if( e2->v2 == v2 ) { v3 = e2->v1; } else { common->Error( "RemoveIfColinear: mislinked edge" ); } if( v1 == v3 ) { common->Error( "RemoveIfColinear: mislinked edge" ); } // they must point in opposite directions dist = ( v3->pv - v2->pv ) * ( v1->pv - v2->pv ); if( dist >= 0 ) { return; } // see if they are colinear dir1 = v3->v.xyz - v1->v.xyz; len = dir1.Normalize(); dir2 = v2->v.xyz - v1->v.xyz; dist = dir2 * dir1; VectorMA( v1->v.xyz, dist, dir1, point ); offset = point - v2->v.xyz; off = offset.Length(); if( off > COLINEAR_EPSILON ) { return; } if( dmapGlobals.drawflag ) { #if 0 qglBegin( GL_LINES ); qglColor3f( 1, 1, 0 ); qglVertex3fv( v1->pv.ToFloatPtr() ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglBegin( GL_LINES ); qglColor3f( 0, 1, 1 ); qglVertex3fv( v2->pv.ToFloatPtr() ); qglVertex3fv( v3->pv.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } // replace the two edges with a single edge UnlinkEdge( e1, island ); UnlinkEdge( e2, island ); // v2 should have no edges now if( v2->edges ) { common->Error( "RemoveIfColinear: didn't remove properly" ); } // if there is an existing edge that already // has these exact verts, we have just collapsed a // sliver triangle out of existance, and all the edges // can be removed for( e = island->edges ; e ; e = e->islandLink ) { if( ( e->v1 == v1 && e->v2 == v3 ) || ( e->v1 == v3 && e->v2 == v1 ) ) { UnlinkEdge( e, island ); RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); return; } } // if we can't add the combined edge, link // the originals back in if( !TryAddNewEdge( v1, v3, island ) ) { e1->islandLink = island->edges; island->edges = e1; LinkEdge( e1 ); e2->islandLink = island->edges; island->edges = e2; LinkEdge( e2 ); return; } // recursively try to combine both verts now, // because things may have changed since the last combine test RemoveIfColinear( v1, island ); RemoveIfColinear( v3, island ); }
/* ===================== SplitOriginalEdgesAtCrossings ===================== */ void SplitOriginalEdgesAtCrossings( optimizeGroup_t* opt ) { int i, j, k, l; int numOriginalVerts; edgeCrossing_t** crossings; numOriginalVerts = numOptVerts; // now split any crossing edges and create optEdges // linked to the vertexes // debug drawing bounds dmapGlobals.drawBounds = optBounds; dmapGlobals.drawBounds[0][0] -= 2; dmapGlobals.drawBounds[0][1] -= 2; dmapGlobals.drawBounds[1][0] += 2; dmapGlobals.drawBounds[1][1] += 2; // generate crossing points between all the original edges crossings = ( edgeCrossing_t** )Mem_ClearedAlloc( numOriginalEdges * sizeof( *crossings ), TAG_TOOLS ); for( i = 0 ; i < numOriginalEdges ; i++ ) { if( dmapGlobals.drawflag ) { #if 0 DrawOriginalEdges( numOriginalEdges, originalEdges ); qglBegin( GL_LINES ); qglColor3f( 0, 1, 0 ); qglVertex3fv( originalEdges[i].v1->pv.ToFloatPtr() ); qglColor3f( 0, 0, 1 ); qglVertex3fv( originalEdges[i].v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } for( j = i + 1 ; j < numOriginalEdges ; j++ ) { optVertex_t* v1, *v2, *v3, *v4; optVertex_t* newVert; edgeCrossing_t* cross; v1 = originalEdges[i].v1; v2 = originalEdges[i].v2; v3 = originalEdges[j].v1; v4 = originalEdges[j].v2; if( !EdgesCross( v1, v2, v3, v4 ) ) { continue; } // this is the only point in optimization where // completely new points are created, and it only // happens if there is overlapping coplanar // geometry in the source triangles newVert = EdgeIntersection( v1, v2, v3, v4, opt ); if( !newVert ) { //common->Printf( "lines %i (%i to %i) and %i (%i to %i) are colinear\n", i, v1 - optVerts, v2 - optVerts, // j, v3 - optVerts, v4 - optVerts ); // !@# // colinear, so add both verts of each edge to opposite if( VertexBetween( v3, v1, v2 ) ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = v3; cross->next = crossings[i]; crossings[i] = cross; } if( VertexBetween( v4, v1, v2 ) ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = v4; cross->next = crossings[i]; crossings[i] = cross; } if( VertexBetween( v1, v3, v4 ) ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = v1; cross->next = crossings[j]; crossings[j] = cross; } if( VertexBetween( v2, v3, v4 ) ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = v2; cross->next = crossings[j]; crossings[j] = cross; } continue; } #if 0 if( newVert && newVert != v1 && newVert != v2 && newVert != v3 && newVert != v4 ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) cross at new point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } else if( newVert ) { common->Printf( "lines %i (%i to %i) and %i (%i to %i) intersect at old point %i\n", i, v1 - optVerts, v2 - optVerts, j, v3 - optVerts, v4 - optVerts, newVert - optVerts ); } #endif if( newVert != v1 && newVert != v2 ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = newVert; cross->next = crossings[i]; crossings[i] = cross; } if( newVert != v3 && newVert != v4 ) { cross = ( edgeCrossing_t* )Mem_ClearedAlloc( sizeof( *cross ), TAG_TOOLS ); cross->ov = newVert; cross->next = crossings[j]; crossings[j] = cross; } } } // now split each edge by its crossing points // colinear edges will have duplicated edges added, but it won't hurt anything for( i = 0 ; i < numOriginalEdges ; i++ ) { edgeCrossing_t* cross, *nextCross; int numCross; optVertex_t** sorted; numCross = 0; for( cross = crossings[i] ; cross ; cross = cross->next ) { numCross++; } numCross += 2; // account for originals sorted = ( optVertex_t** )Mem_Alloc( numCross * sizeof( *sorted ), TAG_TOOLS ); sorted[0] = originalEdges[i].v1; sorted[1] = originalEdges[i].v2; j = 2; for( cross = crossings[i] ; cross ; cross = nextCross ) { nextCross = cross->next; sorted[j] = cross->ov; Mem_Free( cross ); j++; } // add all possible fragment combinations that aren't divided // by another point for( j = 0 ; j < numCross ; j++ ) { for( k = j + 1 ; k < numCross ; k++ ) { for( l = 0 ; l < numCross ; l++ ) { if( sorted[l] == sorted[j] || sorted[l] == sorted[k] ) { continue; } if( sorted[j] == sorted[k] ) { continue; } if( VertexBetween( sorted[l], sorted[j], sorted[k] ) ) { break; } } if( l == numCross ) { //common->Printf( "line %i fragment from point %i to %i\n", i, sorted[j] - optVerts, sorted[k] - optVerts ); AddEdgeIfNotAlready( sorted[j], sorted[k] ); } } } Mem_Free( sorted ); } Mem_Free( crossings ); Mem_Free( originalEdges ); // check for duplicated edges for( i = 0 ; i < numOptEdges ; i++ ) { for( j = i + 1 ; j < numOptEdges ; j++ ) { if( ( optEdges[i].v1 == optEdges[j].v1 && optEdges[i].v2 == optEdges[j].v2 ) || ( optEdges[i].v1 == optEdges[j].v2 && optEdges[i].v2 == optEdges[j].v1 ) ) { common->Printf( "duplicated optEdge\n" ); } } } if( dmapGlobals.verbose ) { common->Printf( "%6i original edges\n", numOriginalEdges ); common->Printf( "%6i edges after splits\n", numOptEdges ); common->Printf( "%6i original vertexes\n", numOriginalVerts ); common->Printf( "%6i vertexes after splits\n", numOptVerts ); } }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw( int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty ) { int i, j; int start, end; if ( !tr.registered ) { return; } R_IssuePendingRenderCommands(); if ( tess.numIndexes ) { RB_EndSurface(); } // we definately want to sync every frame for the cinematics qglFinish(); start = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows ) { ri.Error( ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows ); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; #ifdef USE_OPENGLES qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #else qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); #endif qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } else { if ( dirty ) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); #ifdef USE_OPENGLES GLfloat tex[] = { 0.5f / cols, 0.5f / rows, ( cols - 0.5f ) / cols , 0.5f / rows, ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows, 0.5f / cols, ( rows - 0.5f ) / rows }; GLfloat vtx[] = { x, y, x+w, y, x+w, y+h, x, y+h }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (glcol) qglDisableClientState(GL_COLOR_ARRAY); if (!text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 0, tex ); qglVertexPointer ( 2, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (!text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState(GL_COLOR_ARRAY); #else qglBegin( GL_QUADS ); qglTexCoord2f( 0.5f / cols, 0.5f / rows ); qglVertex2f( x, y ); qglTexCoord2f( ( cols - 0.5f ) / cols, 0.5f / rows ); qglVertex2f( x + w, y ); qglTexCoord2f( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f( x + w, y + h ); qglTexCoord2f( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f( x, y + h ); qglEnd(); #endif }
void RB_DoShadowTessEnd( vec3_t lightPos ) { int i; int numTris; vec3_t lightDir; if ( glConfig.stencilBits < 4 ) { return; } #if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww vec3_t worldxyz; vec3_t entLight; float groundDist; VectorCopy( backEnd.currentEntity->lightDir, entLight ); entLight[2] = 0.0f; VectorNormalize(entLight); //Oh well, just cast them straight down no matter what onto the ground plane. //This presets no chance of screwups and still looks better than a stupid //shader blob. VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { //add or.origin to vert xyz to end up with world oriented coord, then figure //out the ground pos for the vert to project the shadow volume to VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz); groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane; groundDist += 16.0f; //fudge factor VectorMA( tess.xyz[i], -groundDist, lightDir, shadowXyz[i] ); } #else if (lightPos) { for ( i = 0 ; i < tess.numVertexes ; i++ ) { shadowXyz[i][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f); shadowXyz[i][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f); shadowXyz[i][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f); } } else { VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] ); } } #endif // decide which triangles face the light memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; if (!lightPos) { VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); } else { float planeEq[4]; planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]); planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]); planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]); planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) + v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) + v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) ); d = planeEq[0]*lightPos[0]+ planeEq[1]*lightPos[1]+ planeEq[2]*lightPos[2]+ planeEq[3]; } if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } GL_Bind( tr.whiteImage ); //qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); #ifndef _DEBUG_STENCIL_SHADOWS qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); #else qglColor3f( 1.0f, 0.0f, 0.0f ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //qglDisable(GL_DEPTH_TEST); #endif #ifdef _STENCIL_REVERSE qglDepthFunc(GL_LESS); //now using the Carmack Reverse<tm> -rww if ( backEnd.viewParms.isMirror ) { //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } else { //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } qglDepthFunc(GL_LEQUAL); #else // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } #endif // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); #ifdef _DEBUG_STENCIL_SHADOWS qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif }
/* ================ RB_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky(void) { if (r_fastsky->integer) { return; } // when portal sky exists, only render skybox for the portal sky scene if (skyboxportal && !(backEnd.refdef.rdflags & RDF_SKYBOXPORTAL)) { return; } // does the current fog require fastsky? if (backEnd.viewParms.glFog.registered) { if (!backEnd.viewParms.glFog.drawsky) { return; } } else if (glfogNum > FOG_NONE) { if (!glfogsettings[FOG_CURRENT].drawsky) { return; } } backEnd.refdef.rdflags |= RDF_DRAWINGSKY; // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons(&tess); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if (r_showsky->integer) { qglDepthRange(0.0, 0.0); } else { qglDepthRange(1.0, 1.0); } GL_Cull(CT_TWO_SIDED); // draw the outer skybox if (tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage) { qglColor3f(tr.identityLight, tr.identityLight, tr.identityLight); qglPushMatrix(); GL_State(0); qglTranslatef(backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]); DrawSkyBox(tess.shader); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData(&tess); RB_StageIteratorGeneric(); // draw the inner skybox if (tess.shader->sky.innerbox[0] && tess.shader->sky.innerbox[0] != tr.defaultImage) { qglColor3f(tr.identityLight, tr.identityLight, tr.identityLight); qglPushMatrix(); GL_State(0); qglTranslatef(backEnd.viewParms.orientation.origin[0], backEnd.viewParms.orientation.origin[1], backEnd.viewParms.orientation.origin[2]); DrawSkyBoxInner(tess.shader); qglPopMatrix(); } // back to normal depth range qglDepthRange(0.0, 1.0); backEnd.refdef.rdflags &= ~RDF_DRAWINGSKY; // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }
/* ======================================================================================================================= ======================================================================================================================= */ void CNewTexWnd::OnPaint() { CPaintDC dc(this); // device context for painting int nOld = g_qeglobals.d_texturewin.m_nTotalHeight; //hdcTexture = GetDC(); if (!qwglMakeCurrent(dc.GetSafeHdc(), win32.hGLRC)) { common->Printf("ERROR: wglMakeCurrent failed..\n "); } else { const char *name; qglClearColor ( g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], 0 ); qglViewport(0, 0, rectClient.Width(), rectClient.Height()); qglScissor(0, 0, rectClient.Width(), rectClient.Height()); qglMatrixMode(GL_PROJECTION); qglLoadIdentity(); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); qglDisable(GL_DEPTH_TEST); qglDisable(GL_BLEND); qglOrtho(0, rectClient.Width(), origin.y - rectClient.Height(), origin.y, -100, 100); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // init stuff current.x = 8; current.y = -8; currentRow = 0; currentIndex = 0; while (1) { const idMaterial *mat = NextPos(); if (mat == NULL) { break; } int width = mat->GetEditorImage()->uploadWidth * ((float)g_PrefsDlg.m_nTextureScale / 100); int height = mat->GetEditorImage()->uploadHeight * ((float)g_PrefsDlg.m_nTextureScale / 100); // Is this texture visible? if ((draw.y - height - FONT_HEIGHT < origin.y) && (draw.y > origin.y - rectClient.Height())) { // if in use, draw a background qglLineWidth(1); qglColor3f(1, 1, 1); globalImages->BindNull(); qglBegin(GL_LINE_LOOP); qglVertex2f(draw.x - 1, draw.y + 1 - FONT_HEIGHT); qglVertex2f(draw.x - 1, draw.y - height - 1 - FONT_HEIGHT); qglVertex2f(draw.x + 1 + width, draw.y - height - 1 - FONT_HEIGHT); qglVertex2f(draw.x + 1 + width, draw.y + 1 - FONT_HEIGHT); qglEnd(); // Draw the texture float fScale = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? ((float)g_PrefsDlg.m_nTextureScale / 100) : 1.0; mat->GetEditorImage()->Bind(); QE_CheckOpenGLForErrors(); qglColor3f(1, 1, 1); qglBegin(GL_QUADS); qglTexCoord2f(0, 0); qglVertex2f(draw.x, draw.y - FONT_HEIGHT); qglTexCoord2f(1, 0); qglVertex2f(draw.x + width, draw.y - FONT_HEIGHT); qglTexCoord2f(1, 1); qglVertex2f(draw.x + width, draw.y - FONT_HEIGHT - height); qglTexCoord2f(0, 1); qglVertex2f(draw.x, draw.y - FONT_HEIGHT - height); qglEnd(); // draw the selection border if ( !idStr::Icmp(g_qeglobals.d_texturewin.texdef.name, mat->GetName()) ) { qglLineWidth(3); qglColor3f(1, 0, 0); globalImages->BindNull(); qglBegin(GL_LINE_LOOP); qglVertex2f(draw.x - 4, draw.y - FONT_HEIGHT + 4); qglVertex2f(draw.x - 4, draw.y - FONT_HEIGHT - height - 4); qglVertex2f(draw.x + 4 + width, draw.y - FONT_HEIGHT - height - 4); qglVertex2f(draw.x + 4 + width, draw.y - FONT_HEIGHT + 4); qglEnd(); qglLineWidth(1); } // draw the texture name globalImages->BindNull(); qglColor3f(1, 1, 1); qglRasterPos2f(draw.x, draw.y - FONT_HEIGHT + 2); // don't draw the directory name for (name = mat->GetName(); *name && *name != '/' && *name != '\\'; name++) { ; } if (!*name) { name = mat->GetName(); } else { name++; } qglCallLists(strlen(name), GL_UNSIGNED_BYTE, name); //qglCallLists(va("%s -- %d, %d" strlen(name), GL_UNSIGNED_BYTE, name); } } g_qeglobals.d_texturewin.m_nTotalHeight = abs(draw.y) + 100; // reset the current texture globalImages->BindNull(); qglFinish(); qwglSwapBuffers(dc.GetSafeHdc()); TRACE("Texture Paint\n"); } if (g_PrefsDlg.m_bTextureScrollbar && (m_bNeedRange || g_qeglobals.d_texturewin.m_nTotalHeight != nOld)) { m_bNeedRange = false; SetScrollRange(SB_VERT, 0, g_qeglobals.d_texturewin.m_nTotalHeight, TRUE); } //ReleaseDC(hdcTexture); }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd( void ) { int i; int numTris; vec3_t lightDir; GLboolean rgba[4]; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } // decide which triangles face the light Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } // draw the silhouette edges GL_Bind( tr.whiteImage ); qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); }
/* =================== RB_StageIteratorLightmappedMultitexture =================== */ void RB_StageIteratorLightmappedMultitexture(void) { shaderCommands_t *input = &tess; shader_t *shader = input->shader; // log this call if (r_logFile->integer) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment(va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name)); } // set GL fog SetIteratorFog(); // set face culling appropriately GL_Cull(shader->cullType); // set color, pointers, and lock GL_State(GLS_DEFAULT); qglVertexPointer(3, GL_FLOAT, 16, input->xyz); #ifdef REPLACE_MODE qglDisableClientState(GL_COLOR_ARRAY); qglColor3f(1, 1, 1); qglShadeModel(GL_FLAT); #else qglEnableClientState(GL_COLOR_ARRAY); qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.constantColor255); #endif // select base stage GL_SelectTexture(0); qglEnableClientState(GL_TEXTURE_COORD_ARRAY); R_BindAnimatedImage(&tess.xstages[0]->bundle[0]); qglTexCoordPointer(2, GL_FLOAT, 8, tess.texCoords0); // configure second stage GL_SelectTexture(1); qglEnable(GL_TEXTURE_2D); if (r_lightmap->integer) { GL_TexEnv(GL_REPLACE); } else { GL_TexEnv(GL_MODULATE); } // modified for snooper if (tess.xstages[0]->bundle[1].isLightmap && (backEnd.refdef.rdflags & RDF_SNOOPERVIEW)) { GL_Bind(tr.whiteImage); } else { R_BindAnimatedImage(&tess.xstages[0]->bundle[1]); } qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglTexCoordPointer(2, GL_FLOAT, 8, tess.texCoords1); // lock arrays if (qglLockArraysEXT) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment("glLockArraysEXT\n"); } R_DrawElements(input->numIndexes, input->indexes); // disable texturing on TEXTURE1, then select TEXTURE0 qglDisable(GL_TEXTURE_2D); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); GL_SelectTexture(0); #ifdef REPLACE_MODE GL_TexEnv(GL_MODULATE); qglShadeModel(GL_SMOOTH); #endif // now do any dynamic lighting needed //if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) if (tess.dlightBits && tess.shader->fogPass && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))) { if (r_dynamiclight->integer == 2) { DynamicLightPass(); } else { DynamicLightSinglePass(); } } // now do fog if (tess.fogNum && tess.shader->fogPass) { RB_FogPass(); } // unlock arrays if (qglUnlockArraysEXT) { qglUnlockArraysEXT(); GLimp_LogComment("glUnlockArraysEXT\n"); } }
void RB_StageIteratorLightmappedMultitexture( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; // // log this call // if ( r_logFile->integer ) { // don't just call LogComment, or we will get // a call to va() every frame! GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) ); } // // set GL fog // SetIteratorFog(); // // set face culling appropriately // GL_Cull( shader->cullType ); // // set color, pointers, and lock // GL_State( GLS_DEFAULT ); qglVertexPointer( 3, GL_FLOAT, 16, input->xyz ); #ifdef REPLACE_MODE qglDisableClientState( GL_COLOR_ARRAY ); qglColor3f( 1, 1, 1 ); qglShadeModel( GL_FLAT ); #else qglEnableClientState( GL_COLOR_ARRAY ); qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 ); #endif // // select base stage // GL_SelectTexture( 0 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); R_BindAnimatedImage( &tess.xstages[0]->bundle[0] ); qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] ); // // configure second stage // GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); if ( r_lightmap->integer ) { GL_TexEnv( GL_REPLACE ); } else { GL_TexEnv( GL_MODULATE ); } R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] ); // // lock arrays // if ( qglLockArraysEXT ) { qglLockArraysEXT(0, input->numVertexes); GLimp_LogComment( "glLockArraysEXT\n" ); } R_DrawElements( input->numIndexes, input->indexes ); // // disable texturing on TEXTURE1, then select TEXTURE0 // qglDisable( GL_TEXTURE_2D ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); GL_SelectTexture( 0 ); #ifdef REPLACE_MODE GL_TexEnv( GL_MODULATE ); qglShadeModel( GL_SMOOTH ); #endif // // now do any dynamic lighting needed // if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) { ProjectDlightTexture(); } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } }
/* ================ DrawNormals Draws vertex normals for debugging ================ */ static void DrawNormals(shaderCommands_t *input) { vec3_t temp; GL_Bind(tr.whiteImage); qglColor3f(1, 1, 1); qglDepthRange(0, 0); // never occluded GL_State(GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE); // light direction if (r_shownormals->integer == 2) { trRefEntity_t *ent = backEnd.currentEntity; vec3_t temp2; if (ent->e.renderfx & RF_LIGHTING_ORIGIN) { VectorSubtract(ent->e.lightingOrigin, backEnd.orientation.origin, temp2); } else { VectorClear(temp2); } temp[0] = DotProduct(temp2, backEnd.orientation.axis[0]); temp[1] = DotProduct(temp2, backEnd.orientation.axis[1]); temp[2] = DotProduct(temp2, backEnd.orientation.axis[2]); qglColor3f(ent->ambientLight[0] / 255, ent->ambientLight[1] / 255, ent->ambientLight[2] / 255); qglPointSize(5); qglBegin(GL_POINTS); qglVertex3fv(temp); qglEnd(); qglPointSize(1); if (fabs(VectorLengthSquared(ent->lightDir) - 1.0f) > 0.2f) { qglColor3f(1, 0, 0); } else { qglColor3f(ent->directedLight[0] / 255, ent->directedLight[1] / 255, ent->directedLight[2] / 255); } qglLineWidth(3); qglBegin(GL_LINES); qglVertex3fv(temp); VectorMA(temp, 32, ent->lightDir, temp); qglVertex3fv(temp); qglEnd(); qglLineWidth(1); } // normals drawing else { int i; qglBegin(GL_LINES); for (i = 0 ; i < input->numVertexes ; i++) { qglVertex3fv(input->xyz[i].v); VectorMA(input->xyz[i].v, r_normallength->value, input->normal[i].v, temp); qglVertex3fv(temp); } qglEnd(); } qglDepthRange(0, 1); }
/* ============= RE_StretchRaw FIXME: not exactly backend Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle. Used for cinematics. ============= */ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; if ( !tr.registered ) { return; } R_SyncRenderThread(); // we definately want to sync every frame for the cinematics qglFinish(); start = 0; if ( r_speeds->integer ) { start = ri.Milliseconds(); } // make sure rows and cols are powers of 2 for ( i = 0 ; ( 1 << i ) < cols ; i++ ) { } for ( j = 0 ; ( 1 << j ) < rows ; j++ ) { } if ( ( 1 << i ) != cols || ( 1 << j ) != rows) { ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } GL_Bind( tr.scratchImage[client] ); // if the scratchImage isn't in the format we want, specify it as a new texture if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing // it and don't try and do a texture compression qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } if ( r_speeds->integer ) { end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start ); } RB_SetGL2D(); qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglBegin (GL_QUADS); qglTexCoord2f ( 0.5f / cols, 0.5f / rows ); qglVertex2f (x, y); qglTexCoord2f ( ( cols - 0.5f ) / cols , 0.5f / rows ); qglVertex2f (x+w, y); qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x+w, y+h); qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows ); qglVertex2f (x, y+h); qglEnd (); }
/* =============== CreateOptTri =============== */ static void CreateOptTri( optVertex_t* first, optEdge_t* e1, optEdge_t* e2, optIsland_t* island ) { optEdge_t* opposite = NULL; optVertex_t* second = NULL, *third = NULL; optTri_t* optTri = NULL; mapTri_t* tri = NULL; if( e1->v1 == first ) { second = e1->v2; } else if( e1->v2 == first ) { second = e1->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); } if( e2->v1 == first ) { third = e2->v2; } else if( e2->v2 == first ) { third = e2->v1; } else { common->Error( "CreateOptTri: mislinked edge" ); } if( !IsTriangleValid( first, second, third ) ) { common->Error( "CreateOptTri: invalid" ); } //DrawEdges( island ); // identify the third edge if( dmapGlobals.drawflag ) { #if 0 qglColor3f( 1, 1, 0 ); qglBegin( GL_LINES ); qglVertex3fv( e1->v1->pv.ToFloatPtr() ); qglVertex3fv( e1->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); qglColor3f( 0, 1, 1 ); qglBegin( GL_LINES ); qglVertex3fv( e2->v1->pv.ToFloatPtr() ); qglVertex3fv( e2->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } for( opposite = second->edges ; opposite ; ) { if( opposite != e1 && ( opposite->v1 == third || opposite->v2 == third ) ) { break; } if( opposite->v1 == second ) { opposite = opposite->v1link; } else if( opposite->v2 == second ) { opposite = opposite->v2link; } else { common->Error( "BuildOptTriangles: mislinked edge" ); } } if( !opposite ) { common->Printf( "Warning: BuildOptTriangles: couldn't locate opposite\n" ); return; } if( dmapGlobals.drawflag ) { #if 0 qglColor3f( 1, 0, 1 ); qglBegin( GL_LINES ); qglVertex3fv( opposite->v1->pv.ToFloatPtr() ); qglVertex3fv( opposite->v2->pv.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } // create new triangle optTri = ( optTri_t* )Mem_Alloc( sizeof( *optTri ), TAG_TOOLS ); optTri->v[0] = first; optTri->v[1] = second; optTri->v[2] = third; optTri->midpoint = ( optTri->v[0]->pv + optTri->v[1]->pv + optTri->v[2]->pv ) * ( 1.0f / 3.0f ); optTri->next = island->tris; island->tris = optTri; if( dmapGlobals.drawflag ) { #if 0 qglColor3f( 1, 1, 1 ); qglPointSize( 4 ); qglBegin( GL_POINTS ); qglVertex3fv( optTri->midpoint.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } // find the midpoint, and scan through all the original triangles to // see if it is inside any of them for( tri = island->group->triList ; tri ; tri = tri->next ) { if( PointInTri( optTri->midpoint, tri, island ) ) { break; } } if( tri ) { optTri->filled = true; } else { optTri->filled = false; } if( dmapGlobals.drawflag ) { #if 0 if( optTri->filled ) { qglColor3f( ( 128 + orandom.RandomInt( 127 ) ) / 255.0, 0, 0 ); } else { qglColor3f( 0, ( 128 + orandom.RandomInt( 127 ) ) / 255.0, 0 ); } qglBegin( GL_TRIANGLES ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINE_LOOP ); qglVertex3fv( optTri->v[0]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[1]->pv.ToFloatPtr() ); qglVertex3fv( optTri->v[2]->pv.ToFloatPtr() ); qglEnd(); qglFlush(); #endif } // link the triangle to it's edges LinkTriToEdge( optTri, e1 ); LinkTriToEdge( optTri, e2 ); LinkTriToEdge( optTri, opposite ); }