//------------------------------------------------------------------------------------ // прорисовка фонта в 3д пространстве //------------------------------------------------------------------------------------ void vw_DrawFont3D(float X, float Y, float Z, const char *Text, ...) { if (Text == 0) return; // смотрим значения параметров в строке char text[1024]; va_list ap; va_start(ap, Text); vsprintf(text, Text, ap); va_end(ap); // в text уже полная строка if (strlen(text) == 0) return; // прорисовка текста const char *textdraw = text; float Xstart = 0.0f; // сразу определяем "базовую" ширину пробела float SpaceWidth = vw_FindFontCharByUTF32(0x020)->AdvanceX; // чтобы было более читаемо - делаем пробел не менее 2/3 ширины if (SpaceWidth < (InternalFontSize * 0.65f)) SpaceWidth = InternalFontSize * 0.65f; textdraw = text; // для отрисовки eTexture* CurrentTexture = 0; int k=0; // буфер для последовательности RI_QUADS // войдет RI_2f_XY | RI_2f_TEX #ifdef USE_GLES float tmp[(2+2)*6*strlen(textdraw)]; #else float tmp[(2+2)*4*strlen(textdraw)]; #endif // установка свойств текстуры vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA); // всегда стаим белый цвет vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f); vw_PushMatrix(); vw_Translate(VECTOR3D(X, Y, Z)); VECTOR3D CurrentCameraRotation; vw_GetCameraRotation(&CurrentCameraRotation); // поворачиваем к камере vw_Rotate(CurrentCameraRotation.y, 0.0f, 1.0f, 0.0f); vw_Rotate(CurrentCameraRotation.x, 1.0f, 0.0f, 0.0f); // прорисовываем все символы while (strlen(textdraw) > 0) { unsigned UTF32; // преобразуем в утф32 и "сдвигаемся" на следующий символ в строке textdraw = utf8_to_utf32(textdraw, &UTF32); // находим наш текущий символ eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32); if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32); // первый символ - запоминаем его текстуру if (CurrentTexture == 0) CurrentTexture = DrawChar->CharTexture; // проверка на текстуру, если текстура поменялась - отрисовываем все что есть в буфере, если там что-то есть if (CurrentTexture != DrawChar->CharTexture) { // если что-то было в буфере - выводим if (k > 0) { // Установка текстуры vw_SetTexture(0, CurrentTexture); // отрисовываем все что есть в буфере vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float)); } // запоминаем новую текстуру CurrentTexture = DrawChar->CharTexture; // сбрасываем счетчики k=0; } // если не пробел - рисуем if (UTF32 != 0x020) { float DrawX = Xstart + DrawChar->Left; float DrawY = InternalFontSize - DrawChar->Top; float ImageHeight = DrawChar->CharTexture->Height*1.0f; float ImageWidth = DrawChar->CharTexture->Width*1.0f; float FrameHeight = (DrawChar->TexturePositionBottom*1.0f )/ImageHeight; float FrameWidth = (DrawChar->TexturePositionRight*1.0f )/ImageWidth; float Yst = (DrawChar->TexturePositionTop*1.0f)/ImageHeight; float Xst = (DrawChar->TexturePositionLeft*1.0f)/ImageWidth; #ifdef USE_GLES tmp[k++] = DrawX/10.0f; tmp[k++] = (DrawY + DrawChar->Height)/10.0f; tmp[k++] = Xst; tmp[k++] = 1.0f-Yst; tmp[k++] = DrawX/10.0f; tmp[k++] = (DrawY + DrawChar->Height)/10.0f; tmp[k++] = Xst; tmp[k++] = 1.0f-Yst; tmp[k++] = DrawX/10.0f; tmp[k++] = DrawY/10.0f; tmp[k++] = Xst; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = (DrawX + DrawChar->Width)/10.0f; tmp[k++] = (DrawY + DrawChar->Height)/10.0f; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-Yst; tmp[k++] = (DrawX + DrawChar->Width)/10.0f; tmp[k++] = DrawY/10.0f; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = (DrawX + DrawChar->Width)/10.0f; tmp[k++] = DrawY/10.0f; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-FrameHeight; #else tmp[k++] = DrawX/10.0f; tmp[k++] = (DrawY + DrawChar->Height)/10.0f; tmp[k++] = Xst; tmp[k++] = 1.0f-Yst; tmp[k++] = DrawX/10.0f; tmp[k++] = DrawY/10.0f; tmp[k++] = Xst; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = (DrawX + DrawChar->Width)/10.0f; tmp[k++] = DrawY/10.0f; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = (DrawX + DrawChar->Width)/10.0f; tmp[k++] = (DrawY + DrawChar->Height)/10.0f; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-Yst; #endif Xstart += DrawChar->AdvanceX; } else { Xstart += SpaceWidth; } } // если что-то было в буфере - выводим if (k > 0) { // Установка текстуры vw_SetTexture(0, CurrentTexture); // отрисовываем все что есть в буфере #ifdef USE_GLES vw_SendVertices(RI_QUADS, 6*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float)); #else vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float)); #endif } vw_PopMatrix(); vw_SetTextureBlend(false, 0, 0); vw_BindTexture(0, 0); }
//------------------------------------------------------------------------------------ // Прорисовка второго слоя "пыли" с тайловой анимацией //------------------------------------------------------------------------------------ void StarSystemDrawSecondLayer(int DrawType) { if (Setup.VisualEffectsQuality <= 1) { int VFV = RI_3f_XYZ | RI_4f_COLOR | RI_1_TEX; float *buff; buff = new float[4*9]; if (buff == 0) return; float width_2, heigh_2, length_2; width_2 = 0.0f; heigh_2 = 110.0f; length_2 = 110.0f; float x,y,z; x = GamePoint.x; y = GamePoint.y; z = GamePoint.z; float StartTransparentLayer2 = 0.9f; float EndTransparentLayer2 = 0.7f; if (DrawType == 2) { width_2 = length_2 = 175.0f; heigh_2 = 0.0f; VECTOR3D CurrentCameraLocation; vw_GetCameraLocation(&CurrentCameraLocation); x = GamePoint.x+GameCameraGetDeviation()*2.0f + CurrentCameraLocation.x*0.5f; y = GamePoint.y-GameCameraGetDeviation(); z = GamePoint.z+25.0f; StartTransparentLayer2 = StarsTileStartTransparentLayer2; EndTransparentLayer2 = StarsTileEndTransparentLayer2; } int k=0; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer2; buff[k++] = 3.2f; buff[k++] = 0.0f+StarsTile2; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer2; buff[k++] = 3.2f; buff[k++] = 3.0f+StarsTile2; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer2; buff[k++] = 0.2f; buff[k++] = 0.0f+StarsTile2; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer2; buff[k++] = 0.2f; buff[k++] = 3.0f+StarsTile2; if (DrawType == 1) { StarsTile2 -= 0.04f*(vw_GetTime() - StarsTileUpdateTime2); StarsTileUpdateTime2 = vw_GetTime(); } else { StarsTile2 -= 0.12f*(vw_GetTime(1) - StarsTileUpdateTime2); StarsTileUpdateTime2 = vw_GetTime(1); } if (StarsTile2 < -3.0f) StarsTile2 += 3.0f; eTexture *TileTexture = vw_FindTextureByName("DATA/SKYBOX/tile_stars.tga"); vw_SetTexture(0, TileTexture); // по умолчанию всегда трилинейная фильтрация, если надо - ставим билинейную if (Setup.TextureFilteringMode == 1) vw_SetTextureFiltering(RI_TEXTURE_BILINEAR); vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_ONE); vw_DepthTest(false, -1); if (DrawType == 1) { vw_PushMatrix(); vw_Rotate(-20.0f, 0.0f, 0.0f, 1.0f); vw_Rotate(-45.0f, 0.0f, 1.0f, 0.0f); vw_Rotate(30.0f, 1.0f, 0.0f, 0.0f); } vw_SendVertices(RI_TRIANGLE_STRIP, 4, VFV, buff, 9*sizeof(float)); if (DrawType == 1) vw_PopMatrix(); vw_DepthTest(true, RI_LESSEQUAL); vw_SetTextureBlend(false, 0, 0); vw_BindTexture(0, 0); if (buff != 0){delete [] buff; buff = 0;} } }
//----------------------------------------------------------------------------- // прорисовка системы //----------------------------------------------------------------------------- void CSpaceStars::Draw() { // загрузка текстуры, уже должна быть подключена if (Texture == 0) return; VECTOR3D CurrentCameraRotation; vw_GetCameraRotation(&CurrentCameraRotation); // если еще нет последовательности, или камеру повернули - надо пересчитать прорисовку if ((tmpDATA == 0 && VBO == 0) || CurrentCameraRotation.x != LastCameraAngleX || CurrentCameraRotation.y != LastCameraAngleY || CurrentCameraRotation.z != LastCameraAngleZ) { if (list != 0){delete [] list; list = 0;} if (tmpDATA != 0){delete [] tmpDATA; tmpDATA = 0;} if (VBO!=0){vw_DeleteVBO(*VBO); delete VBO; VBO=0;} // находим реальное кол-во частиц на прорисовку CStar *tmp = Start; PrimitCount = 0; // сохраняем данные LastCameraAngleX = CurrentCameraRotation.x; LastCameraAngleY = CurrentCameraRotation.y; LastCameraAngleZ = CurrentCameraRotation.z; // получаем текущее положение камеры VECTOR3D CurrentCameraLocation; vw_GetCameraLocation(&CurrentCameraLocation); while (tmp!=0) { CStar *tmp2 = tmp->Next; // небольшая оптимизация, если попадает в сферу - рисуем, нет - значит не видно if (vw_SphereInFrustum(tmp->Location + CurrentCameraLocation, Size)) PrimitCount++; tmp = tmp2; } // если рисовать нечего - выходим if (PrimitCount == 0) return; // список, в котором они будут упорядочены list = new CStar*[PrimitCount]; if (list == 0) return; int LenCount = 0; float *Len = 0; tmp = Start; while (tmp!=0) { CStar *tmp2 = tmp->Next; // небольшая оптимизация, если попадает в сферу - рисуем, нет - значит не видно if (vw_SphereInFrustum(tmp->Location + CurrentCameraLocation, Size)) { list[LenCount] = tmp; LenCount++; } tmp = tmp2; } // если не поддерживаем/не включены шейдеры, или нет поддержки вбо // делаем старым способом, через временный буфер if (!Setup.UseGLSL) { // делаем массив для всех элементов #ifdef USE_GLES // войдет RI_3f_XYZ | RI_2f_TEX | RI_4ub_COLOR tmpDATA = new float[6*(3+2+1)*PrimitCount]; if (tmpDATA == 0) return; #else // войдет RI_3f_XYZ | RI_2f_TEX | RI_4ub_COLOR tmpDATA = new float[4*(3+2+1)*PrimitCount]; if (tmpDATA == 0) return; #endif GLubyte *tmpDATAub = (GLubyte *)tmpDATA; // номер float'а в последовательности int k=0; for (int i=0; i<PrimitCount; i++) { // находим вектор камера-точка VECTOR3D nnTmp; // смотрим, если есть не нужно поворачивать, работаем с направлением nnTmp = list[i]->Location^(-1.0f); nnTmp.Normalize(); // находим перпендикуляр к вектору nnTmp VECTOR3D nnTmp2; nnTmp2.x = 1.0f; nnTmp2.y = 1.0f; nnTmp2.z = -(nnTmp.x + nnTmp.y)/nnTmp.z; nnTmp2.Normalize(); // находим перпендикуляр к векторам nnTmp и nnTmp2 // файтически - a x b = ( aybz - byaz , azbx - bzax , axby - bxay ); VECTOR3D nnTmp3; nnTmp3.x = nnTmp.y*nnTmp2.z - nnTmp2.y*nnTmp.z; nnTmp3.y = nnTmp.z*nnTmp2.x - nnTmp2.z*nnTmp.x; nnTmp3.z = nnTmp.x*nnTmp2.y - nnTmp2.x*nnTmp.y; nnTmp3.Normalize(); // находим VECTOR3D tmpAngle1,tmpAngle2,tmpAngle3,tmpAngle4; tmpAngle1 = nnTmp3^(Size*1.5f); tmpAngle3 = nnTmp3^(-Size*1.5f); tmpAngle2 = nnTmp2^(Size*1.5f); tmpAngle4 = nnTmp2^(-Size*1.5f); GLubyte A = (GLubyte)(list[i]->Alpha*255); // собираем четырехугольник #ifdef USE_GLES tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 1.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 1.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle2.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle2.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle2.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle4.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle4.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle4.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 1.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 0.0f; #else tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 1.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle2.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle2.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle2.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle4.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle4.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle4.z; // Z tmpDATAub[k*sizeof(float)] = 204; tmpDATAub[k*sizeof(float)+1] = 204; tmpDATAub[k*sizeof(float)+2] = 255; tmpDATAub[k*sizeof(float)+3] = A; k++; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 1.0f; #endif } } else { // все нормально, работаем с шейдерами и вбо // делаем массив для всех элементов #ifdef USE_GLES // войдет RI_3f_XYZ | RI_2f_TEX | RI_3f_NORMAL*/ tmpDATA = new float[6*(3+2+3)*PrimitCount]; if (tmpDATA == 0) return; #else // войдет RI_3f_XYZ | RI_2f_TEX | RI_3f_NORMAL*/ tmpDATA = new float[4*(3+2+3)*PrimitCount]; if (tmpDATA == 0) return; #endif // номер float'а в последовательности int k=0; for (int i=0; i<PrimitCount; i++) { // находим вектор камера-точка VECTOR3D nnTmp; // смотрим, если есть не нужно поворачивать, работаем с направлением nnTmp = list[i]->Location^(-1.0f); nnTmp.Normalize(); // находим перпендикуляр к вектору nnTmp VECTOR3D nnTmp2; nnTmp2.x = 1.0f; nnTmp2.y = 1.0f; nnTmp2.z = -(nnTmp.x + nnTmp.y)/nnTmp.z; nnTmp2.Normalize(); // находим перпендикуляр к векторам nnTmp и nnTmp2 // файтически - a x b = ( aybz - byaz , azbx - bzax , axby - bxay ); VECTOR3D nnTmp3; nnTmp3.x = nnTmp.y*nnTmp2.z - nnTmp2.y*nnTmp.z; nnTmp3.y = nnTmp.z*nnTmp2.x - nnTmp2.z*nnTmp.x; nnTmp3.z = nnTmp.x*nnTmp2.y - nnTmp2.x*nnTmp.y; nnTmp3.Normalize(); // находим VECTOR3D tmpAngle1,tmpAngle2,tmpAngle3,tmpAngle4; tmpAngle1 = nnTmp3^(Size*1.5f); tmpAngle3 = nnTmp3^(-Size*1.5f); tmpAngle2 = nnTmp2^(Size*1.5f); tmpAngle4 = nnTmp2^(-Size*1.5f); // собираем четырехугольник tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = list[i]->AlphaDelta; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 1.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle2.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle2.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle2.z; // Z tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = list[i]->AlphaDelta; tmpDATA[k++] = 0.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = 0.0f;// не задействован tmpDATA[k++] = list[i]->AlphaDelta; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 0.0f; tmpDATA[k++] = list[i]->Location.x+tmpAngle4.x; // X tmpDATA[k++] = list[i]->Location.y+tmpAngle4.y; // Y tmpDATA[k++] = list[i]->Location.z+tmpAngle4.z; // Z tmpDATA[k++] = 1.0f;// не задействован tmpDATA[k++] = 1.0f;// не задействован tmpDATA[k++] = list[i]->AlphaDelta; tmpDATA[k++] = 1.0f; tmpDATA[k++] = 1.0f; } if (CAPS->VBOSupported) { VBO = new unsigned int; if (!vw_BuildVBO(4*PrimitCount, tmpDATA, 8, VBO)) { delete VBO; VBO = 0; } else { // только если поддерживае вбо, иначе им рисуем if (tmpDATA != 0){delete [] tmpDATA; tmpDATA = 0;} } } if (list != 0){delete [] list; list = 0;} } if (Len != 0){delete [] Len; Len = 0;} } if (PrimitCount > 0) { vw_SetTexture(0, Texture); vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_ONE); // получаем текущее положение камеры VECTOR3D CurrentCameraLocation; vw_GetCameraLocation(&CurrentCameraLocation); CurrentCameraLocation += VECTOR3D(GameCameraGetDeviation()*0.9,-GameCameraGetDeviation()*0.5f,0.0f); vw_PushMatrix(); vw_Translate(CurrentCameraLocation); if (!Setup.UseGLSL) { #ifdef USE_GLES vw_SendVertices(RI_QUADS, 6*PrimitCount, RI_3f_XYZ | RI_4ub_COLOR | RI_1_TEX, tmpDATA, 6*sizeof(float)); #else vw_SendVertices(RI_QUADS, 4*PrimitCount, RI_3f_XYZ | RI_4ub_COLOR | RI_1_TEX, tmpDATA, 6*sizeof(float)); #endif } else { if (GLSL != 0) { vw_UseShaderProgram(GLSL); vw_Uniform1i(GLSL, UniformLocations[0], 0); vw_Uniform1f(GLSL, UniformLocations[1], Age); } vw_SendVertices(RI_QUADS, 4*PrimitCount, RI_3f_XYZ | RI_1_TEX | RI_3f_NORMAL, tmpDATA, 8*sizeof(float), VBO); if (GLSL != 0) vw_StopShaderProgram(); } vw_PopMatrix(); vw_SetTextureBlend(false, 0, 0); } vw_BindTexture(0, 0); }
//------------------------------------------------------------------------------------ // StarSystem draw function //------------------------------------------------------------------------------------ void StarSystemDraw(int DrawType) { if (!StarSystem_InitedAll) return; // current camera location VECTOR3D CurrentCameraLocation; vw_GetCameraLocation(&CurrentCameraLocation); vw_DepthTest(false, -1); if (StarSystem_Inited) { // SkyBox vw_PushMatrix(); vw_Translate(CurrentCameraLocation); vw_Rotate(StarSystem_BaseRotation.x, 1.0f, 0.0f, 0.0f); vw_Rotate(StarSystem_BaseRotation.y, 0.0f, 1.0f, 0.0f); vw_Rotate(StarSystem_BaseRotation.z, 0.0f, 0.0f, 1.0f); SkyBoxDraw(); vw_PopMatrix(); } // static space stars if (psSpaceStatic!=0) psSpaceStatic->Draw(); vw_DepthTest(true, RI_LESSEQUAL); // космические объекты // рисуем планеты и большие астероиды _до_ тайловой анимации CSpaceObject *tmp1 = StartSpaceObject; while (tmp1!=0) { CSpaceObject *tmp2 = tmp1->Next; // если это планета на заднем фоне if (tmp1->ObjectType == 14) { if (DrawType == 2) { vw_PushMatrix(); vw_Translate(VECTOR3D(CurrentCameraLocation.x*0.90f-GameCameraGetDeviation()*4.0f, GameCameraGetDeviation()*2.0f,0.0f)); } tmp1->Draw(false); if (DrawType == 2) vw_PopMatrix(); } else // если это большой астероид летящий на заднем фоне if (tmp1->ObjectType == 15 && (tmp1->ObjectCreationType>10 && tmp1->ObjectCreationType<20)) { if (DrawType == 2) { vw_PushMatrix(); vw_Translate(VECTOR3D(CurrentCameraLocation.x*0.70f-GameCameraGetDeviation()*4.0f, GameCameraGetDeviation()*2.0f,0.0f)); } tmp1->Draw(false); if (DrawType == 2) vw_PopMatrix(); } tmp1 = tmp2; } // очищаем буфер глубины, чтобы "3д подложка" не участвовала в проверке глубины vw_Clear(RI_DEPTH_BUFFER); //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Прорисовка подложки с тайловой анимацией //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ { int VFV = RI_3f_XYZ | RI_4f_COLOR | RI_1_TEX; float *buff = 0; buff = new float[4*9]; if (buff == 0) return; float width_2, heigh_2, length_2; width_2 = 0.0f; heigh_2 = 110.0f; length_2 = 110.0f; float x,y,z; x = GamePoint.x; y = GamePoint.y; z = GamePoint.z; float StartTransparentLayer1 = 0.7f; float EndTransparentLayer1 = 0.7f; if (DrawType == 2) { width_2 = length_2 = 175.0f; heigh_2 = 0.0f; // чем ниже слой, тем меньше его двигаем при перемещении камеры (при стандартном аспект рейшен) x = GamePoint.x+GameCameraGetDeviation() + CurrentCameraLocation.x*0.8f; y = GamePoint.y-GameCameraGetDeviation()*0.5f; z = GamePoint.z+25.0f; StartTransparentLayer1 = StarsTileStartTransparentLayer1; EndTransparentLayer1 = StarsTileEndTransparentLayer1; } int k=0; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer1; buff[k++] = 1.0f; buff[k++] = 0.0f+StarsTile/3.0f; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer1; buff[k++] = 1.0f; buff[k++] = 1.0f+StarsTile/3.0f; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer1; buff[k++] = 0.0f; buff[k++] = 0.0f+StarsTile/3.0f; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer1; buff[k++] = 0.0f; buff[k++] = 1.0f+StarsTile/3.0f; if (DrawType == 1) { StarsTile -= 0.015f*(vw_GetTime() - StarsTileUpdateTime); StarsTileUpdateTime = vw_GetTime(); } else { StarsTile -= 0.035f*(vw_GetTime(1) - StarsTileUpdateTime); StarsTileUpdateTime = vw_GetTime(1); } if (StarsTile < -3.0f) StarsTile += 3.0f; eTexture *TileTexture = vw_FindTextureByName("DATA/SKYBOX/tile_back.tga"); vw_SetTexture(0, TileTexture); // по умолчанию всегда трилинейная фильтрация, если надо - ставим билинейную if (Setup.TextureFilteringMode == 1) vw_SetTextureFiltering(RI_TEXTURE_BILINEAR); vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_ONE); vw_DepthTest(false, -1); if (DrawType == 1) { vw_PushMatrix(); vw_Rotate(-20.0f, 0.0f, 0.0f, 1.0f); vw_Rotate(-45.0f, 0.0f, 1.0f, 0.0f); vw_Rotate(30.0f, 1.0f, 0.0f, 0.0f); } vw_SendVertices(RI_TRIANGLE_STRIP, 4, VFV, buff, 9*sizeof(float)); // звезды рисуем отдельно, четкими (со своими текстурными координатами) k=0; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer1; buff[k++] = 3.0f; buff[k++] = 0.0f+StarsTile; buff[k++] = x + width_2; buff[k++] = y + heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer1; buff[k++] = 3.0f; buff[k++] = 3.0f+StarsTile; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z + length_2+length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = StartTransparentLayer1; buff[k++] = 0.0f; buff[k++] = 0.0f+StarsTile; buff[k++] = x - width_2; buff[k++] = y - heigh_2; buff[k++] = z - length_2/2; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = 1.0f; buff[k++] = EndTransparentLayer1; buff[k++] = 0.0f; buff[k++] = 3.0f+StarsTile; vw_SetTexture(0, vw_FindTextureByName("DATA/SKYBOX/tile_stars.tga")); vw_SendVertices(RI_TRIANGLE_STRIP, 4, VFV, buff, 9*sizeof(float)); if (DrawType == 1) vw_PopMatrix(); vw_DepthTest(true, RI_LESSEQUAL); vw_SetTextureBlend(false, 0, 0); vw_BindTexture(0, 0); if (buff != 0){delete [] buff; buff = 0;} } // корректируем положение частиц "космической пыли", если в игре и камера движется if (DrawType == 2) { VECTOR3D TMPpsSpace; psSpace->GetLocation(&TMPpsSpace); psSpace->SetStartLocation(TMPpsSpace); psSpace->MoveSystemLocation(VECTOR3D(0,10,250)+GamePoint); } }
//------------------------------------------------------------------------------------ // прорисовка фонта //------------------------------------------------------------------------------------ void vw_DrawFont(int X, int Y, float FlattenWidth, float MaxWidth, float FontScale, float R, float G, float B, float Transp, const char *Text, ...) { if (Text == 0) return; // учитываем аспект рейшен float AW; float AH; bool ASpresent=false; ASpresent = vw_GetAspectWH(&AW, &AH); // получаем данные текущего вьюпорта int W, H; vw_GetViewport(0, 0, &W, &H); float AHw = H*1.0f; float RealTextYPos = AHw - 2*Y + 4 + InternalFontSize*FontScale; if (ASpresent) RealTextYPos = AH - 2*Y + 4 + InternalFontSize*FontScale; // если текст ниже чем ширина нашего окна - не рисуем if (ASpresent){ if (Y > AH) return;} else {if (Y > H) return;} // если текст выше чем ноль - тоже рисовать его смысла нет if (Y+InternalFontSize*FontScale < 0) return; // FlattenWidth - выравнивать по ширине // если FlattenWidth отрицателен, выравниваем по значению, "сжимая" буквы, если нужно // MaxWidth - рисовать до ширины // смотрим значения параметров в строке char text[1024]; va_list ap; va_start(ap, Text); vsprintf(text, Text, ap); va_end(ap); // в text уже полная строка if (strlen(text) == 0) return; float Xstart = X; // сразу определяем "базовую" ширину пробела, чтобы учитывать в расчетах float SpaceWidth = vw_FindFontCharByUTF32(0x020)->AdvanceX*FontScale; // чтобы было более читаемо - делаем пробел не менее 2/3 ширины if (SpaceWidth < (InternalFontSize * 0.65f)) SpaceWidth = InternalFontSize * 0.65f; // коэф. изменения букв по ширине float FontWidthScale = 1.0f; if (Transp >= 1.0f) Transp = 1.0f; // если нужно выравнивать, считаем данные пробелов if (FlattenWidth > 0) { float LineWidth = 0; int SpaceCount = 0; const char *CountCheck = text; while (strlen(CountCheck) > 0) { unsigned UTF32; // преобразуем в утф32 и "сдвигаемся" на следующий символ в строке CountCheck = utf8_to_utf32(CountCheck, &UTF32); // находим наш текущий символ eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32); if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32); // считаем кол-во пробелов if (UTF32 == 0x020) SpaceCount++; else LineWidth += DrawChar->AdvanceX; } if (FlattenWidth > LineWidth) if (SpaceCount!=0) SpaceWidth = (FlattenWidth - LineWidth)/SpaceCount; } // если нужно сжать, считаем коэф. сжатия букв if (FlattenWidth < 0) { float LineWidth = 0; const char *CountCheck = text; while (strlen(CountCheck) > 0) { unsigned UTF32; // преобразуем в утф32 и "сдвигаемся" на следующий символ в строке CountCheck = utf8_to_utf32(CountCheck, &UTF32); // находим наш текущий символ eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32); if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32); // считаем длину символов с пробелами if (UTF32 != 0x020) LineWidth += DrawChar->AdvanceX; else LineWidth += SpaceWidth; } if (FlattenWidth*(-1.0f) < LineWidth) FontWidthScale = FlattenWidth/LineWidth*(-1.0f); } float LineWidth = 0; // установка свойств текстуры vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA); // ставим цвет vw_SetColor(R, G, B, Transp); // для отрисовки eTexture* CurrentTexture = 0; int k=0; // буфер для последовательности RI_QUADS // войдет RI_2f_XYZ | RI_2f_TEX #ifdef USE_GLES GLshort *tmp = 0; tmp = new GLshort[(2+2)*6*strlen(text)]; if (tmp == 0) return; #else float *tmp = 0; tmp = new float[(2+2)*4*strlen(text)]; if (tmp == 0) return; #endif // чтобы меньше делать операций умножения, включаем коэф. один в другой сразу для ширины символов FontWidthScale = FontScale*FontWidthScale; // прорисовка текста const char *textdraw = text; // прорисовываем все символы while (strlen(textdraw) > 0) { unsigned UTF32; // преобразуем в утф32 и "сдвигаемся" на следующий символ в строке textdraw = utf8_to_utf32(textdraw, &UTF32); // находим наш текущий символ eFontChar* DrawChar = vw_FindFontCharByUTF32(UTF32); if (DrawChar == 0) DrawChar = vw_LoadFontChar(UTF32); // первый символ - запоминаем его текстуру if (CurrentTexture == 0) CurrentTexture = DrawChar->CharTexture; // проверка на текстуру, если текстура поменялась - отрисовываем все что есть в буфере, если там что-то есть if (CurrentTexture != DrawChar->CharTexture) { // если что-то было в буфере - выводим if (k > 0) { // Установка текстуры vw_SetTexture(0, CurrentTexture); // отрисовываем все что есть в буфере #ifdef USE_GLES vw_MatrixMode(RI_TEXTURE_MATRIX); vw_LoadIdentity(); vw_Scale(1.0f/CurrentTexture->Width,1.0f/CurrentTexture->Height,1.0f); vw_PushMatrix(); vw_MatrixMode(RI_MODELVIEW_MATRIX); vw_SendVertices(RI_TRIANGLES, 6*(k/24), RI_2s_XY | RI_2s_TEX | RI_1_TEX, tmp, 4*sizeof(GLshort)); vw_PopMatrix(); vw_MatrixMode(RI_TEXTURE_MATRIX); vw_LoadIdentity(); #else vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float)); #endif } // запоминаем новую текстуру CurrentTexture = DrawChar->CharTexture; // сбрасываем счетчики k=0; } #ifdef USE_GLES float DrawX = (Xstart + DrawChar->Left*FontWidthScale); float DrawY = (Y + 2 + (InternalFontSize - DrawChar->Top)*FontScale); // 2 доп смещение ("привет" от старого фонта) // Вычисление поправки по У в зависимости от DrawCorner // - расположения угла начала координат float tmpPosY = 0; // изменяем только в случае RI_UL_CORNER if (ASpresent) tmpPosY = (AH - DrawY - DrawY - DrawChar->Height*FontScale); else tmpPosY = (AHw - DrawY - DrawY - DrawChar->Height*FontScale); // если не пробел - рисуем if (UTF32 != 0x020) { GLshort ImageHeight = DrawChar->CharTexture->Height; GLshort ImageWidth = DrawChar->CharTexture->Width; GLshort FrameHeight = (DrawChar->TexturePositionBottom); GLshort FrameWidth = (DrawChar->TexturePositionRight); GLshort Yst = (DrawChar->TexturePositionTop); GLshort Xst = (DrawChar->TexturePositionLeft); tmp[k++] = (GLshort)DrawX; tmp[k++] = (GLshort)(DrawY + tmpPosY + DrawChar->Height*FontScale); tmp[k++] = Xst; tmp[k++] = ImageHeight-Yst; tmp[k++] = (GLshort)DrawX; tmp[k++] = (GLshort)(DrawY + tmpPosY); tmp[k++] = Xst; tmp[k++] = ImageHeight-FrameHeight; tmp[k++] = (GLshort)(DrawX + DrawChar->Width*FontWidthScale); tmp[k++] = (GLshort)(DrawY + tmpPosY + DrawChar->Height*FontScale); tmp[k++] = FrameWidth; tmp[k++] = ImageHeight-Yst; tmp[k++] = (GLshort)DrawX; tmp[k++] = (GLshort)(DrawY + tmpPosY); tmp[k++] = Xst; tmp[k++] = ImageHeight-FrameHeight; tmp[k++] = (GLshort)(DrawX + DrawChar->Width*FontWidthScale); tmp[k++] = (GLshort)(DrawY + tmpPosY); tmp[k++] = FrameWidth; tmp[k++] = ImageHeight-FrameHeight; tmp[k++] = (GLshort)(DrawX + DrawChar->Width*FontWidthScale); tmp[k++] = (GLshort)(DrawY + tmpPosY + DrawChar->Height*FontScale); tmp[k++] = FrameWidth; tmp[k++] = ImageHeight-Yst; Xstart += (DrawChar->Width + DrawChar->Left)*FontWidthScale; LineWidth += (DrawChar->Width + DrawChar->Left)*FontWidthScale; } else { Xstart += SpaceWidth*FontWidthScale; LineWidth += SpaceWidth*FontWidthScale; } #else // если не пробел - рисуем if (UTF32 != 0x020) { float DrawX = Xstart + DrawChar->Left*FontWidthScale; float DrawY = Y + GlobalFontOffsetY + (InternalFontSize - DrawChar->Top)*FontScale; // Вычисление поправки по У в зависимости от DrawCorner // - расположения угла начала координат float tmpPosY = 0; // изменяем только в случае RI_UL_CORNER if (ASpresent) tmpPosY = (AH - DrawY - DrawY - DrawChar->Height*FontScale); else tmpPosY = (AHw - DrawY - DrawY - DrawChar->Height*FontScale); float ImageHeight = DrawChar->CharTexture->Height*1.0f; float ImageWidth = DrawChar->CharTexture->Width*1.0f; float FrameHeight = (DrawChar->TexturePositionBottom*1.0f )/ImageHeight; float FrameWidth = (DrawChar->TexturePositionRight*1.0f )/ImageWidth; float Yst = (DrawChar->TexturePositionTop*1.0f)/ImageHeight; float Xst = (DrawChar->TexturePositionLeft*1.0f)/ImageWidth; tmp[k++] = DrawX; tmp[k++] = DrawY +tmpPosY + DrawChar->Height*FontScale; tmp[k++] = Xst; tmp[k++] = 1.0f-Yst; tmp[k++] = DrawX; tmp[k++] = DrawY +tmpPosY; tmp[k++] = Xst; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = DrawX + DrawChar->Width*FontWidthScale; tmp[k++] = DrawY +tmpPosY; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-FrameHeight; tmp[k++] = DrawX + DrawChar->Width*FontWidthScale; tmp[k++] = DrawY +tmpPosY + DrawChar->Height*FontScale; tmp[k++] = FrameWidth; tmp[k++] = 1.0f-Yst; Xstart += DrawChar->AdvanceX*FontWidthScale; LineWidth += DrawChar->AdvanceX*FontWidthScale; } else { Xstart += SpaceWidth*FontWidthScale; LineWidth += SpaceWidth*FontWidthScale; } #endif // если нужно прорисовывать с ограничением по длине if (MaxWidth != 0.0f) if (LineWidth >= MaxWidth) break; } // если что-то было в буфере - выводим if (k > 0) { // Установка текстуры vw_SetTexture(0, CurrentTexture); // отрисовываем все что есть в буфере #ifdef USE_GLES vw_MatrixMode(RI_TEXTURE_MATRIX); vw_LoadIdentity(); vw_Scale(1.0f/CurrentTexture->Width,1.0f/CurrentTexture->Height,1.0f); vw_MatrixMode(RI_MODELVIEW_MATRIX); vw_PushMatrix(); vw_SendVertices(RI_TRIANGLES, 6*(k/24), RI_2s_XY | RI_2s_TEX | RI_1_TEX, tmp, 4*sizeof(GLshort)); vw_PopMatrix(); vw_MatrixMode(RI_TEXTURE_MATRIX); vw_LoadIdentity(); #else vw_SendVertices(RI_QUADS, 4*(k/16), RI_2f_XY | RI_1_TEX, tmp, 4*sizeof(float)); #endif } if (tmp != 0){delete [] tmp; tmp = 0;} vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f); vw_SetTextureBlend(false, 0, 0); vw_BindTexture(0, 0); }