/************************************************************************ * Copyright (c) 2005-2007 tok@openlinux.org.uk * * * * This software is provided as-is, without any express or implied * * warranty. In no event will the authors be held liable for any * * damages arising from the use of this software. * * * * Permission is granted to anyone to use this software for any purpose, * * including commercial applications, and to alter it and redistribute * * it freely, subject to the following restrictions: * * * * 1. The origin of this software must not be misrepresented; you must * * not claim that you wrote the original software. If you use this * * software in a product, an acknowledgment in the product documentation * * would be appreciated but is not required. * * * * 2. Altered source versions must be plainly marked as such, and must * * not be misrepresented as being the original software. * * * * 3. This notice may not be removed or altered from any source * * distribution. * ************************************************************************/ #include #include #include "gl_cityview.h" #include "gl_spritecache.h" #include "spritemanager.h" #include "buffercache.h" #include "gl_camera.h" #include "dataholder.h" #include "math3d.h" #include "localplayer.h" #include "log.h" #include "gl_screen.h" #include "blockdata.h" #include "image_loader.h" #include "blockanim.h" #include "id_sys.h" #include "map_helper.h" float slope_height_offset(unsigned char slope_type, float dx, float dz); namespace OpenGTA { /* float slope_raw_data[45][5][4][3] = { #include "slope1_data.h" }; float slope_tex_data[45][4][4][2] = { #include "slope1_tcoords.h" }; float lid_normal_data[45][3] = { #include "lid_normal_data.h" }; */ /* GLuint createGLTexture(GLsizei w, GLsizei h, bool rgba, const void* pixels) { GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (rgba) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); //gluBuild2DMipmaps(GL_TEXTURE_2D, 4, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); //gluBuild2DMipmaps(GL_TEXTURE_2D, 3, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixels); GL_CHECKERROR; return tex; } */ struct GLColor { GLfloat rgb[3]; GLColor() { rgb[0] = rgb[1] = rgb[2] = 0; } GLColor(GLfloat i) { rgb[0] = rgb[1] = rgb[2] = i; } GLColor(GLfloat r, GLfloat g, GLfloat b) { rgb[0] = r; rgb[1] = g; rgb[2] = b; } }; GLColor block_colors[8] = { GLColor(1), // air GLColor(0, 0, 1), // water GLColor(0, 1, 1), // road GLColor(1, 0, 0), // pavement GLColor(0, 1, 0), // field GLColor(1, 1, 0), // building GLColor(1), // unused GLColor(1) // unused }; GLfloat* map_block_type_color(uint8_t k) { // k = 6 now used to fix pavement cols if (k == 7) WARN << "block-type: " << int(k) << " should be unused!" << std::endl; if (k < 8) return block_colors[k].rgb; ERROR << "Invalid block-type: " << int(k) << std::endl; return block_colors[0].rgb; } CityView::CityView() { setNull(); /* Pedestrian p(Vector3D(0.5f, 0.5f, 0.5f), Vector3D(4, 5.01f, 4), 0xffffffff); p.m_control = &LocalPlayer::Instance(); SpriteManagerHolder::Instance().addPed(p); */ } void CityView::setNull() { loadedMap = NULL; sideCache = NULL; lidCache = NULL; auxCache = NULL; blockAnims = NULL; camVec[0] = 0.0f; camVec[1] = 1.0f; camVec[2] = 0.0f; zoomLevel = 1.0f; visibleRange = 15; topDownView = true; drawTextured = true; drawLines = false; drawLinesBlockType = true; setPosition(0.0f, 0.0f, 20.0f); scene_display_list = 0; texFlipTest = 0; drawHeadingMarkers = false; current_sector = NULL; } CityView::~CityView() { cleanup(); } void CityView::resetTextures() { sideCache->clearAll(); lidCache->clearAll(); auxCache->clearAll(); } void CityView::setVisibleRange(int r) { visibleRange = r; scene_is_dirty = true; } int CityView::getVisibleRange() { return visibleRange; } bool CityView::getDrawTextured() { return drawTextured; } bool CityView::getDrawLines() { return drawLines; } bool CityView::getDrawLinesBlockColor() { return drawLinesBlockType; } void CityView::setDrawTextured(bool v) { drawTextured = v; } void CityView::setDrawLines(bool v) { drawLines= v; } void CityView::setDrawLinesBlockColor(bool v) { drawLinesBlockType= v; } void CityView::cleanup() { //if (loadedMap) // delete loadedMap; if (sideCache) delete sideCache; if (lidCache) delete lidCache; if (auxCache) delete auxCache; if (blockAnims) delete blockAnims; if (scene_display_list) glDeleteLists(scene_display_list, 1); setNull(); } void CityView::setViewMode(bool topDown) { topDownView = topDown; } void CityView::loadMap(const std::string &map, const std::string &style_f) { cleanup(); //loadedMap = new Map(map); MapHolder::Instance().load(map); loadedMap = &MapHolder::Instance().get(); StyleHolder::Instance().load(style_f); style = &StyleHolder::Instance().get(); style->setDeltaHandling(true); /* for (size_t i = 0; i < style->carInfos.size(); ++i) { OpenGTA::GraphicsBase::CarInfo * cinfo = style->carInfos[i]; assert(cinfo); INFO << cinfo->numDoors << std::endl; }*/ sideCache = new OpenGL::TextureCache("SideCache"); lidCache = new OpenGL::TextureCache("LidCache"); auxCache = new OpenGL::TextureCache("AuxCache"); sideCache->setClearMagic(5); lidCache->setClearMagic(8); auxCache->setClearMagic(5); blockAnims = new BlockAnimCtrl(style->animations); scene_is_dirty = true; lastCacheEmptyTicks = 0; scene_display_list = glGenLists(1); SpriteManagerHolder::Instance().clear(); // safeguard against double car entries (in nyc.cmp) Util::MapOfPair2Int d_car_map; for (PHYSFS_uint16 oc = 0; oc < loadedMap->numObjects; oc++) { OpenGTA::Map::ObjectPosition & op = loadedMap->objects[oc]; if (op.remap >= 128) { if (Util::item_count(d_car_map, op.x, op.y) == 0) Util::register_item1(d_car_map, op.x, op.y); else continue; } createLevelObject(&loadedMap->objects[oc]); } //SpriteManagerHolder::Instance().trainSystem.loadStations(*loadedMap); activeRect.x = activeRect.y = 0; activeRect.w = activeRect.h = 0; } void CityView::createLevelObject(OpenGTA::Map::ObjectPosition *obj) { SpriteManager & s_man = SpriteManagerHolder::Instance(); uint32_t id = TypeIdBlackBox::requestId(); if (obj->remap >= 128) { Car car(*obj, id); s_man.add(car); } else { SpriteObject gobj(*obj, id); s_man.add(gobj); } } void CityView::setZoom(const GLfloat zoom) { zoomLevel = zoom; } void CityView::setPosition(const GLfloat & x, const GLfloat & y, const GLfloat & z) { camPos[0] = x; camPos[1] = y; camPos[2] = z; scene_is_dirty = true; //INFO << "Position: " << x << ", " << z << " (" << y << ")" << std::endl; if (loadedMap) { PHYSFS_uint8 _x = PHYSFS_uint8((x >= 1.0f) ? ((x < 255.0f) ? x : 254) : 1); // FIXME: crashes on 0 or 255 PHYSFS_uint8 _y = PHYSFS_uint8((z >= 1.0f) ? ((z < 255.0f) ? z : 254) : 1); // why??? NavData::Sector* in_sector = loadedMap->nav->getSectorAt(_x, _y); assert(in_sector); if (in_sector != current_sector) { current_sector = in_sector; } } //if (loadedMap && !topDownView) // getTerrainHeight(camPos[0], camPos[1], camPos[2]); } NavData::Sector* CityView::getCurrentSector() { return current_sector; } /* void CityView::setCamVector(const GLfloat & x, const GLfloat & y, const GLfloat & z) { camVec[1] = x; camVec[2] = y; camVec[3] = z; scene_is_dirty = true; } */ void CityView::setTopDownView(const GLfloat & height) { camPos[1] = height; scene_is_dirty = true; setViewMode(true); } void CityView::getTerrainHeight(GLfloat & x, GLfloat & y, GLfloat & z) { int xi = int(x); int yi = int(z); //int zi = int(z); float h = 0.5f; WARN << "THIS FUNCTION SHOULD NOT BE USED!" << std::endl; PHYSFS_uint16 emptycount = loadedMap->getNumBlocksAt(xi, yi); for (int c=6-emptycount; c >= 1; c--) { OpenGTA::Map::BlockInfo* bi = loadedMap->getBlockAt(xi, yi, c); if (bi->blockType() == 0) { //camPos[1] = h; break; } /*INFO << "block " << c << " lid: " << int(bi->lid) << std::endl; if (bi->blockType() > 0) { INFO << "not air but: " << int(bi->blockType()) << std::endl; }*/ h += 1.0f; } y = h; } OpenGL::PagedTexture CityView::renderMap2Texture() { OpenGL::Screen & screen = OpenGL::ScreenHolder::Instance(); uint32_t width = screen.getWidth(); uint32_t height = screen.getHeight(); uint32_t gl_h = 1; while (gl_h < height) gl_h <<= 1; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glFinish(); Vector3D v_off(0,0,0); int persp_find_done = 0; int break_loop_safe = 500; while (persp_find_done != 3) { OpenGL::ScreenHolder::Instance().set3DProjection(); glRotatef(180, 0, 0, 1); gluLookAt(128+v_off.x, 230, 128+v_off.y, 128+v_off.x, 0, 128+v_off.y, 0.0f, 0.0f, 1.0f); GLint viewport[4]; GLdouble mvmatrix[16], projmatrix[16]; GLdouble winx, winy, winz; glGetIntegerv (GL_VIEWPORT, viewport); glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); gluProject(0, 0, 0, mvmatrix, projmatrix, viewport, &winx, &winy, &winz); if (winx > 0.5f) v_off.x += 0.2f; else if (winx < -0.5f) v_off.x -= 0.2f; else persp_find_done |= 1; INFO << winx << " " << winy << std::endl; gluProject(256, 0, 256, mvmatrix, projmatrix, viewport, &winx, &winy, &winz); if (winy < -0.5f) v_off.y += 0.2f; else if (winy > 0.5f) v_off.y -= 0.2f; else persp_find_done |= 2; break_loop_safe--; if (break_loop_safe == 0) { WARN << "breaking out of loop - NOT GOOD!" << std::endl; persp_find_done = 3; } INFO << winx << " " << winy << std::endl; } //glTranslatef(-35, 0, 0); for (int i = 0; i <= 255; i++) { for (int j= 0; j <= 255; j++) { glPushMatrix(); glTranslatef(1.0f*j, 0.0f, 1.0f*i); PHYSFS_uint16 maxcount = loadedMap->getNumBlocksAtNew(j,i); for (int c=0; c < maxcount; ++c) { glPushMatrix(); drawBlock(loadedMap->getBlockAtNew(j, i, c)); glPopMatrix(); glTranslatef(0.0f, 1.0f, 0.0f); } glPopMatrix(); } } GL_CHECKERROR; glFinish(); /* GLuint txtnumber; glGenTextures(1, &txtnumber); // Create 1 Texture glBindTexture(GL_TEXTURE_2D, txtnumber); // Bind The Texture GL_CHECKERROR; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, gl_h, gl_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); GL_CHECKERROR; glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width/2, height/2); GL_CHECKERROR; //glViewport(0, 0, width, height); return OpenGL::PagedTexture(txtnumber, 0, 0, 1, 1); */ uint32_t img_size = gl_h * gl_h * 3; uint8_t *img_buf = Util::BufferCacheHolder::Instance().requestBuffer(img_size); glReadBuffer(GL_BACK); //for (uint32_t i = 0; i < gl_h; i++) { // glReadPixels(0, i, gl_h, 1, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)(img_buf + gl_h * 3 * i)); //} glReadPixels(0, 0, gl_h, gl_h, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)img_buf); GL_CHECKERROR; sideCache->sink(); sideCache->sink(); lidCache->sink(); lidCache->sink(); sideCache->clear(); lidCache->clear(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); uint32_t y_off = 100; uint32_t x = 0; while (*(img_buf + y_off * gl_h * 3 + x) == 0 && *(img_buf + y_off * gl_h * 3 + x+1) == 0 && *(img_buf + y_off * gl_h * 3 + x + 2) == 0) x += 3; INFO << "color after x = " << x/3 << std::endl; x = gl_h-3; while (*(img_buf + y_off * gl_h * 3 + x) == 0 && *(img_buf + y_off * gl_h * 3 + x+1) == 0 && *(img_buf + y_off * gl_h * 3 + x+2) == 0) x -= 3; INFO << "color after x = " << x/3 << std::endl; GLuint tex = ImageUtil::createGLTexture(gl_h, gl_h, false, img_buf); float f_h = float(height) / gl_h; float f_w = float(width) / gl_h; //float horiz_corr = (1.0f - f_w) / 2.0f; //return OpenGL::PagedTexture(tex, 0+horiz_corr, 0, f_w+horiz_corr, f_h); return OpenGL::PagedTexture(tex, 0, 0, f_h, f_h); } void CityView::draw(Uint32 ticks) { GL_CHECKERROR; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* sideCache->clearStats(); lidCache->clearStats(); */ glLoadIdentity(); int x1, y1, x2, y2; if (topDownView) { glRotatef(180, 0, 0, 1); gluLookAt(camPos[0], camPos[1], camPos[2], camPos[0], 0.0f, camPos[2], 0.0f, 0.0f, 1.0f); x1 = int(camPos[0]) - visibleRange; y1 = int(camPos[2]) - visibleRange; x2 = int(camPos[0]) + visibleRange; y2 = int(camPos[2]) + visibleRange; } else { OpenGL::Camera & cam = OpenGL::CameraHolder::Instance(); //gluLookAt(camPos[0], camPos[1], camPos[2], camPos[0]+5, 0, (camPos[2])+5, camVec[0], camVec[1], camVec[2]); cam.update(ticks); Vector3D & e = cam.getEye(); //INFO << "eye: " << e.x << ", " << e.y << ", " << e.z << std::endl; setPosition(e.x, e.y, e.z); x1 = int(e.x) - visibleRange; y1 = int(e.z) - visibleRange; x2 = int(e.x) + visibleRange; y2 = int(e.z) + visibleRange; //PHYSFS_uint16 emptycount = loadedMap->getNumBlocksAt(int(e.x),int(e.z)); //INFO << "cam-h is " << int(e.y)<< " ec: " << emptycount << std::endl; /* int cc = 0; for (int i = 6 - emptycount; i >= 0; i--) { OpenGTA::Map::BlockInfo* bi = loadedMap->getBlockAt(int(e.x), int(e.z), i); //INFO << i << " type: "<< int(bi->blockType()) << " lid: " << int(bi->lid)<< std::endl; if (bi->blockType() >=2 && bi->blockType() <= 4) { c.y = c.y - e.y + float(cc)+1.0f; e.y = float(cc)+1.0f; break; } cc++; } */ //getTerrainHeight(e.x, e.y, e.z); } frustum.CalculateFrustum(); if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; if (x2 > 255) x2 = 255; if (y2 > 255) y2 = 255; //INFO << activeRect.x << ", " << activeRect.y << " -> " << // activeRect.x+activeRect.w << ", " << activeRect.y + activeRect.h << std::endl; activeRect.x = x1; activeRect.y = y1; activeRect.w = x2 - x1; activeRect.h = y2 - y1; //INFO << "Active area: " << x1 << " - " << x2 << " , " << y1 << " - " << y2 << std::endl; int xd1, xd2, yd1, yd2; xd2 = 0; yd2 = 0; xd1 = x2; yd1 = y2; bool use_display_list = false; GL_CHECKERROR; if ((!scene_is_dirty) && (use_display_list)) { glCallList(scene_display_list); } else { scene_rendered_blocks = scene_rendered_vertices = 0; if (use_display_list) glNewList(scene_display_list, GL_COMPILE); for (int i = y1; i <= y2; i++) { //glPushMatrix(); //glTranslatef(0.0f, 0.0f, 1.0f*i); for (int j= x1; j <= x2; j++) { if (!frustum.BlockInFrustum(0.5f+j, 0.5f+i, 0.5f)) continue; if (j < xd1) xd1 = j; xd2 = j; if (i < yd1) yd1 = i; yd2 = i; glPushMatrix(); glTranslatef(1.0f*j, 0.0f, 1.0f*i); //PHYSFS_uint16 emptycount = loadedMap->getNumBlocksAt(j,i); PHYSFS_uint16 maxcount = loadedMap->getNumBlocksAtNew(j,i); //for (int c=6-emptycount; c >= 1; c--) { for (int c=0; c < maxcount; ++c) { ++scene_rendered_blocks; glPushMatrix(); if (c < maxcount - 1) { Map::BlockInfo * bi = loadedMap->getBlockAtNew(j, i, c + 1); aboveBlockType = bi->blockType(); } else aboveBlockType = loadedMap->getBlockAtNew(j, i, c)->blockType(); drawBlock(loadedMap->getBlockAtNew(j, i, c)); glPopMatrix(); glTranslatef(0.0f, 1.0f, 0.0f); } glPopMatrix(); } //glPopMatrix(); } drawnRect.x = xd1; drawnRect.y = yd1; drawnRect.w = xd2 - xd1; drawnRect.h = yd2 - yd1; //INFO << "area drawn: " << xd1 << " - " << xd2 << " , " << yd1 << " - " << yd2 << std::endl; if (use_display_list) { glEndList(); glCallList(scene_display_list); scene_is_dirty = false; } //INFO << scene_rendered_blocks << " blocks drawn with " << scene_rendered_vertices << " vertices" << std::endl; } GL_CHECKERROR; /* for (PHYSFS_uint16 oc = 0; oc < loadedMap->numObjects; oc++) { if (frustum.BlockInFrustum((loadedMap->objects[oc].x >> 6) + 0.5f, (loadedMap->objects[oc].y >> 6) + 0.5f, 0.5f)) drawObject(&loadedMap->objects[oc]); }*/ GL_CHECKERROR; SpriteManagerHolder::Instance().drawInRect(activeRect); lastCacheEmptyTicks += ticks; if (lastCacheEmptyTicks > 4000) { lidCache->sink(); lidCache->sink(); sideCache->sink(); sideCache->clear(); lidCache->clear(); lastCacheEmptyTicks = 0; //lidCache->status(); //sideCache->status(); } GL_CHECKERROR; } #if 0 OpenGL::PagedTexture CityView::createSprite(size_t sprite_num, GraphicsBase::SpriteInfo* info) { unsigned char* src = style->getSpriteBitmap(sprite_num, -1 , 0); unsigned int glwidth = 1; unsigned int glheight = 1; while(glwidth < info->w) glwidth <<= 1; while(glheight < info->h) glheight <<= 1; unsigned char* dst = Util::BufferCacheHolder::Instance().requestBuffer(glwidth * glheight * 4); Util::BufferCacheHolder::Instance().unlockBuffer(src); assert(dst != NULL); unsigned char * t = dst; unsigned char * r = src; for (unsigned int i = 0; i < info->h; i++) { memcpy(t, r, info->w * 4); t += glwidth * 4; r += info->w * 4; } GLuint texid; glGenTextures(1, &texid); glBindTexture(GL_TEXTURE_2D, texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst); return OpenGL::PagedTexture(texid, 0, 0, float(info->w)/float(glwidth), float(info->h)/float(glheight)); } #endif void CityView::drawObject(OpenGTA::Map::ObjectPosition* obj) { float w, h; float x = float(obj->x >> 6) + float(obj->x % 64)/64.0f; float y = float(obj->y >> 6) + float(obj->y % 64)/64.0f; float z = float(obj->z >> 6) + float(obj->z % 64)/64.0f; size_t spriteNumAbs, sprNum; GraphicsBase::SpriteInfo *info = NULL; GraphicsBase::SpriteNumbers::SpriteTypes st; if (obj->remap >= 128) { // car GraphicsBase::CarInfo* cinfo = style->findCarByModel(obj->type); assert(cinfo); sprNum = cinfo->sprNum; spriteNumAbs = style->spriteNumbers.reIndex(cinfo->sprNum, GraphicsBase::SpriteNumbers::CAR); info = style->getSprite(spriteNumAbs); w = float(info->w) / 64.0f; h = float(info->h) / 64.0f; st = GraphicsBase::SpriteNumbers::CAR; } else { spriteNumAbs = style->spriteNumbers.reIndex(style->objectInfos[obj->type]->sprNum, GraphicsBase::SpriteNumbers::OBJECT); sprNum = style->objectInfos[obj->type]->sprNum; info = style->getSprite(spriteNumAbs); assert(info); w = float(info->w) / 64.0f; h = float(info->h) / 64.0f; st = GraphicsBase::SpriteNumbers::OBJECT; } OpenGL::PagedTexture t; if (OpenGL::SpriteCacheHolder::Instance().has(spriteNumAbs)) t = OpenGL::SpriteCacheHolder::Instance().get(spriteNumAbs); else { //t = createSprite(spriteNum, info); //OpenGL::SpriteCacheHolder::Instance().add(spriteNum, t); t = OpenGL::SpriteCacheHolder::Instance().create(sprNum, st, -1); } glPushMatrix(); glTranslatef(x, 6.1f - z, y); // ups, seems: up<->down glRotatef(obj->rotation / 1035.0f * 360.0f, 0, 1, 0); // 1035 is guesswork! //glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, t.inPage); glBegin(GL_QUADS); glTexCoord2f(t.coords[0].u, t.coords[1].v); glVertex3f(-w/2, 0.0f, h/2); glTexCoord2f(t.coords[1].u, t.coords[1].v); glVertex3f(w/2, 0.0f, h/2); glTexCoord2f(t.coords[1].u, t.coords[0].v); glVertex3f(w/2, 0.0f, -h/2); glTexCoord2f(t.coords[0].u, t.coords[0].v); glVertex3f(-w/2, 0.0f, -h/2); glEnd(); glPopMatrix(); //glEnable(GL_TEXTURE_2D); } void CityView::drawBlock(OpenGTA::Map::BlockInfo* bi) { GL_CHECKERROR; /* std::cout << "is flat: " << bi->isFlat() << " up ok: " << bi->upOk() << " down " << bi->downOk() << " left " << bi->leftOk() << " right " << bi->rightOk() << std::endl; std::cout << "block type: "<< int(bi->blockType()) << " slope " << int(bi->slopeType()) << " rotation: " << int(bi->rotation()) << " remap: " << int(bi->remapIndex()) << " TB " << bi->flipTopBottom() << " LR " << bi->flipLeftRight() << std::endl; */ uint8_t which = bi->slopeType(); float nx = LID_NORMAL_DATA[which][0]; float ny = LID_NORMAL_DATA[which][1]; float nz = LID_NORMAL_DATA[which][2]; int jj = 0; GLfloat lidTex[8] = {0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f}; //GLfloat sideTex1_bak[8] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; GLfloat sideTex1[8] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f}; #ifdef MSWAP #undef MSWAP #endif #define MSWAP(a,b) { GLfloat tmp = sideTex1[a]; sideTex1[a] = sideTex1[b]; sideTex1[b] = tmp; } #define SLOPE_TEX_CP(k) memcpy(sideTex1, SLOPE_TEX_DATA[which][k], 8 * sizeof(GLfloat)) #ifdef GLTEX_HELPER #undef GLTEX_HELPER #endif #define GLTEX_HELPER \ glTexCoord2f(lidTex[jj], lidTex[jj+1]); jj += 2; if (jj > 6) { jj = 0; } #define GLTEX1_HELPER \ glTexCoord2f(sideTex1[jj], sideTex1[jj+1]); jj += 2; if (jj > 6) { jj = 0; } bool is_flat = bi->isFlat(); // transparency in the texture ? GLuint lid_tex = 0, left_tex = 0, right_tex = 0, top_tex = 0, bottom_tex = 0; // FIXME: no remaps used! if (bi->lid) { int frame_num = -1;//style->checkBlockAnimation(0, bi->lid); BlockAnim * banim = blockAnims->getAnim(1, bi->lid); if (banim) { frame_num = banim->getCurrentFrameNumber(); } if (frame_num <= 0) { if (!lidCache->hasTexture(bi->lid)) { lid_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getLid(static_cast(bi->lid), 0, is_flat)); lidCache->addTexture(bi->lid, lid_tex); } else lid_tex = lidCache->getTextureWithId(bi->lid); } else { uint8_t aux_id = banim->getFrame(frame_num - 1); if (!auxCache->hasTexture(aux_id)) { lid_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getAux(static_cast(aux_id), 0, is_flat)); auxCache->addTexture(aux_id, lid_tex); } else lid_tex = auxCache->getTextureWithId(aux_id); } } if (bi->left) { int frame_num = -1; BlockAnim * banim = blockAnims->getAnim(0, bi->left); if (banim) { frame_num = banim->getCurrentFrameNumber(); } if (frame_num <= 0) { if (!sideCache->hasTexture(bi->left)) { left_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getSide(static_cast(bi->left), 0, is_flat)); sideCache->addTexture(bi->left, left_tex); } else left_tex = sideCache->getTextureWithId(bi->left); } else { uint8_t aux_id = banim->getFrame(frame_num - 1); if (!auxCache->hasTexture(aux_id)) { left_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getAux(static_cast(aux_id), 0, is_flat)); auxCache->addTexture(aux_id, left_tex); } else left_tex = auxCache->getTextureWithId(aux_id); } } if (bi->right) { int frame_num = -1; BlockAnim * banim = blockAnims->getAnim(0, bi->right); if (banim) { frame_num = banim->getCurrentFrameNumber(); } if (frame_num <= 0) { if (!sideCache->hasTexture(bi->right)) { right_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getSide(static_cast(bi->right), 0, is_flat)); sideCache->addTexture(bi->right, right_tex); } else right_tex = sideCache->getTextureWithId(bi->right); } else { uint8_t aux_id = banim->getFrame(frame_num - 1); if (!auxCache->hasTexture(aux_id)) { right_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getAux(static_cast(aux_id), 0, is_flat)); auxCache->addTexture(aux_id, right_tex); } else right_tex = auxCache->getTextureWithId(aux_id); } } if (bi->top) { int frame_num = -1; BlockAnim * banim = blockAnims->getAnim(0, bi->top); if (banim) { frame_num = banim->getCurrentFrameNumber(); } if (frame_num <= 0) { if (!sideCache->hasTexture(bi->top)) { top_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getSide(static_cast(bi->top), 0, is_flat)); sideCache->addTexture(bi->top, top_tex); } else top_tex = sideCache->getTextureWithId(bi->top); } else { uint8_t aux_id = banim->getFrame(frame_num - 1); if (!auxCache->hasTexture(aux_id)) { top_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getAux(static_cast(aux_id), 0, is_flat)); auxCache->addTexture(aux_id, top_tex); } else top_tex = auxCache->getTextureWithId(aux_id); } } if (bi->bottom) { int frame_num = -1; BlockAnim * banim = blockAnims->getAnim(0, bi->bottom); if (banim) { frame_num = banim->getCurrentFrameNumber(); } if (frame_num <= 0) { if (!sideCache->hasTexture(bi->bottom)) { bottom_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getSide(static_cast(bi->bottom), 0, is_flat)); sideCache->addTexture(bi->bottom, bottom_tex); } else bottom_tex = sideCache->getTextureWithId(bi->bottom); } else { uint8_t aux_id = banim->getFrame(frame_num - 1); if (!auxCache->hasTexture(aux_id)) { bottom_tex = ImageUtil::createGLTexture(64, 64, is_flat, style->getAux(static_cast(aux_id), 0, is_flat)); auxCache->addTexture(aux_id, bottom_tex); } else bottom_tex = auxCache->getTextureWithId(aux_id); } } #define RESET_COLOR glColor3f(1, 1, 1) #define COLOR_OFF if (drawLinesBlockType) RESET_COLOR #define COLOR_BY_BLOCK(idx) { GLfloat *_c = map_block_type_color(idx); glColor3f(_c[0], _c[1], _c[2]); } #define COLOR_ON if (drawLinesBlockType) COLOR_BY_BLOCK(aboveBlockType) //#define COLOR_ON if (drawLinesBlockType) COLOR_BY_BLOCK(bi->blockType()) if (drawLinesBlockType) // handle flat/transparent case if (is_flat) { if (bi->lid) { jj = 0; if (bi->typeMap & 16384) { jj += 2; } if (bi->typeMap & 32768) { jj += 4; } if(drawTextured) { glBindTexture(GL_TEXTURE_2D, lid_tex); glBegin(GL_QUADS); glNormal3f(nx, ny, nz); for (int j=0; j < 4; j++) { GLTEX_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][0][j][0], SLOPE_RAW_DATA[which][0][j][1], SLOPE_RAW_DATA[which][0][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][0][j][0], SLOPE_RAW_DATA[which][0][j][1], SLOPE_RAW_DATA[which][0][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][0][0][0], SLOPE_RAW_DATA[which][0][0][1], SLOPE_RAW_DATA[which][0][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } #undef MSWAP #define MSWAP(a, b) { sideTex1[a] = 1.0f - sideTex1[a]; sideTex1[b] = 1.0f - sideTex1[b]; } jj = 0; // only 'lid' rotated if (bi->top) { SLOPE_TEX_CP(1); if (bi->flipTopBottom()) { MSWAP(0, 2); MSWAP(4, 6); } if (drawTextured) { glBindTexture(GL_TEXTURE_2D, top_tex); glBegin(GL_QUADS); for (int j=0; j < 4; j++) { GLTEX1_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][2][j][0], SLOPE_RAW_DATA[which][2][j][1], SLOPE_RAW_DATA[which][2][j][2]); } jj = 0; SLOPE_TEX_CP(0); if (!bi->flipTopBottom()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { GLTEX1_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][1][j][0], SLOPE_RAW_DATA[which][1][j][1], SLOPE_RAW_DATA[which][1][j][2]-1.001f); // -1.001f // offset by .001 to fix NYC bridges; polygon z-fighting } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][2][j][0], SLOPE_RAW_DATA[which][2][j][1], SLOPE_RAW_DATA[which][2][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][2][0][0], SLOPE_RAW_DATA[which][2][0][1], SLOPE_RAW_DATA[which][2][0][2]); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][1][j][0], SLOPE_RAW_DATA[which][1][j][1], SLOPE_RAW_DATA[which][1][j][2]-1.001f); } glVertex3f(SLOPE_RAW_DATA[which][1][0][0], SLOPE_RAW_DATA[which][1][0][1], SLOPE_RAW_DATA[which][1][0][2]-1.001f); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } jj = 0; //memcpy(sideTex1, sideTex1_bak, 8*sizeof(GLfloat)); if (bi->left) { SLOPE_TEX_CP(2); if (bi->flipLeftRight()) { MSWAP(0, 2); MSWAP(4, 6); } if (drawTextured) { glBindTexture(GL_TEXTURE_2D, left_tex); glBegin(GL_QUADS); for (int j=0; j < 4; j++) { GLTEX1_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][3][j][0], SLOPE_RAW_DATA[which][3][j][1], SLOPE_RAW_DATA[which][3][j][2]); } jj = 0; SLOPE_TEX_CP(3); if (!bi->flipLeftRight()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { GLTEX1_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][4][j][0]-1.001f, // -1.001f SLOPE_RAW_DATA[which][4][j][1], SLOPE_RAW_DATA[which][4][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][3][j][0], SLOPE_RAW_DATA[which][3][j][1], SLOPE_RAW_DATA[which][3][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][3][0][0], SLOPE_RAW_DATA[which][3][0][1], SLOPE_RAW_DATA[which][3][0][2]); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][4][j][0]-1.001f, SLOPE_RAW_DATA[which][4][j][1], SLOPE_RAW_DATA[which][4][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][4][0][0]-1.001f, SLOPE_RAW_DATA[which][4][0][1], SLOPE_RAW_DATA[which][4][0][2]); glEnd(); COLOR_OFF; glEnable(GL_TEXTURE_2D); // end-of-lines } } } else { if (bi->lid) { if (drawTextured) { glBindTexture(GL_TEXTURE_2D, lid_tex); jj = 0; if (bi->typeMap & 16384) { jj += 2; } if (bi->typeMap & 32768) { jj += 4; } glBegin(GL_QUADS); glNormal3f(nx, ny, nz); for (int j=0; j < 4; j++) { GLTEX_HELPER; scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][0][j][0], SLOPE_RAW_DATA[which][0][j][1], SLOPE_RAW_DATA[which][0][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][0][j][0], SLOPE_RAW_DATA[which][0][j][1], SLOPE_RAW_DATA[which][0][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][0][0][0], SLOPE_RAW_DATA[which][0][0][1], SLOPE_RAW_DATA[which][0][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } jj = 0; // only 'lid' rotated #undef MSWAP #define MSWAP(a, b) { sideTex1[a] = 1.0f - sideTex1[a]; sideTex1[b] = 1.0f - sideTex1[b]; } /* if (bi->flipTopBottom()) { //MSWAP(1, 5); //MSWAP(3, 7); MSWAP(0, 2); MSWAP(4, 6); }*/ if (bi->top && (which != 42)) { if (drawTextured) { glBindTexture(GL_TEXTURE_2D, top_tex); glBegin(GL_QUADS); SLOPE_TEX_CP(1); if (bi->flipTopBottom()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { //if (!bi->flipTopBottom()) GLTEX1_HELPER; /* glTexCoord2f(SLOPE_TEX_DATA[which][1][j][0], SLOPE_TEX_DATA[which][1][j][1]); */ scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][2][j][0], SLOPE_RAW_DATA[which][2][j][1], SLOPE_RAW_DATA[which][2][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][2][j][0], SLOPE_RAW_DATA[which][2][j][1], SLOPE_RAW_DATA[which][2][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][2][0][0], SLOPE_RAW_DATA[which][2][0][1], SLOPE_RAW_DATA[which][2][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } jj = 0; if (bi->bottom && (which != 41)) { if (drawTextured) { glBindTexture(GL_TEXTURE_2D, bottom_tex); glBegin(GL_QUADS); SLOPE_TEX_CP(0); if (bi->flipTopBottom()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { //if (!bi->flipTopBottom()) GLTEX1_HELPER; /* glTexCoord2f(SLOPE_TEX_DATA[which][0][j][0], SLOPE_TEX_DATA[which][0][j][1]); */ scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][1][j][0], SLOPE_RAW_DATA[which][1][j][1], SLOPE_RAW_DATA[which][1][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][1][j][0], SLOPE_RAW_DATA[which][1][j][1], SLOPE_RAW_DATA[which][1][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][1][0][0], SLOPE_RAW_DATA[which][1][0][1], SLOPE_RAW_DATA[which][1][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } /*memcpy(sideTex1, sideTex1_bak, 8 * sizeof(GLfloat)); if (bi->flipLeftRight()) { MSWAP(0, 2); MSWAP(4, 6); }*/ jj = 0; if (bi->left && (which != 44)) { if (drawTextured) { glBindTexture(GL_TEXTURE_2D, left_tex); glBegin(GL_QUADS); SLOPE_TEX_CP(2); if (bi->flipLeftRight()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { //if (!bi->flipLeftRight()) GLTEX1_HELPER; /* glTexCoord2f(SLOPE_TEX_DATA[which][2][j][0], SLOPE_TEX_DATA[which][2][j][1]); */ scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][3][j][0], SLOPE_RAW_DATA[which][3][j][1], SLOPE_RAW_DATA[which][3][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][3][j][0], SLOPE_RAW_DATA[which][3][j][1], SLOPE_RAW_DATA[which][3][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][3][0][0], SLOPE_RAW_DATA[which][3][0][1], SLOPE_RAW_DATA[which][3][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } jj = 0; if (bi->right && (which != 43)) { if (drawTextured) { glBindTexture(GL_TEXTURE_2D, right_tex); glBegin(GL_QUADS); SLOPE_TEX_CP(3); if (bi->flipLeftRight()) { MSWAP(0, 2); MSWAP(4, 6); } for (int j=0; j < 4; j++) { //if (!bi->flipLeftRight()) GLTEX1_HELPER; /* glTexCoord2f(SLOPE_TEX_DATA[which][3][j][0], SLOPE_TEX_DATA[which][3][j][1]); */ scene_rendered_vertices += 1; glVertex3f(SLOPE_RAW_DATA[which][4][j][0], SLOPE_RAW_DATA[which][4][j][1], SLOPE_RAW_DATA[which][4][j][2]); } glEnd(); } // lines if (drawLines) { glDisable(GL_TEXTURE_2D); COLOR_ON; glBegin(GL_LINE_STRIP); for (int j=0; j < 4; j++) { glVertex3f(SLOPE_RAW_DATA[which][4][j][0], SLOPE_RAW_DATA[which][4][j][1], SLOPE_RAW_DATA[which][4][j][2]); } glVertex3f(SLOPE_RAW_DATA[which][4][0][0], SLOPE_RAW_DATA[which][4][0][1], SLOPE_RAW_DATA[which][4][0][2]); glEnd(); glEnable(GL_TEXTURE_2D); // end-of-lines COLOR_OFF; } } #if 0 for (int i = 0; i < 5; ++i) { // RESEARCH ME: is this correct? needed above as well? if ((which == 41) && (i == 1)) continue; if ((which == 42) && (i == 2)) continue; if ((which == 43) && (i == 4)) continue; if ((which == 44) && (i == 3)) continue; jj = 0; if (i == 0) if (!bi->lid) continue; else { glBindTexture(GL_TEXTURE_2D, lidCache->getTextureWithId(bi->lid)); if (bi->typeMap & 16384) { jj += 2; } if (bi->typeMap & 32768) { jj += 4; } } if (i == 2) if (!bi->top) continue; else glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->top)); if (i == 1) if (!bi->bottom) continue; else glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->bottom)); if (i == 4) if (!bi->right) continue; else glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->right)); if (i == 3) if (!bi->left) continue; else glBindTexture(GL_TEXTURE_2D, sideCache->getTextureWithId(bi->left)); glBegin(GL_QUADS); // FIXME: normals are completely fucked up switch(i) { case 0: glNormal3f(nx, ny, nz); break; case 1: glNormal3f(0.0f, 0.0f, 1.0f); break; case 2: glNormal3f(0.0f, 0.0f, -1.0f); break; case 3: glNormal3f(-1.0f, 0.0f, 0.0f); break; case 4: glNormal3f(1.0f, 0.0f, 0.0f); break; } for (int j=0; j < 4; j++) { GLTEX_HELPER; scene_rendered_vertices += 3; glVertex3f(SLOPE_RAW_DATA[which][i][j][0], SLOPE_RAW_DATA[which][i][j][1], SLOPE_RAW_DATA[which][i][j][2]); } glEnd(); } #endif } // else if (!drawHeadingMarkers) return; float offset_correction = 0.1f; if (which == 0) offset_correction = -0.9f; //glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); #define HEIGHT_VERTEX(a, b, c) glVertex3f(a, offset_correction + slope_height_offset(which, a, c), c) if (bi->downOk()) { glBegin(GL_LINES); HEIGHT_VERTEX(0.5f, 0.1f, 0.2f); HEIGHT_VERTEX(0.5f, 0.1f, 0.8f); HEIGHT_VERTEX(0.45f, 0.1f, 0.7f); HEIGHT_VERTEX(0.5f, 0.1f, 0.8f); HEIGHT_VERTEX(0.55f, 0.1f, 0.7f); HEIGHT_VERTEX(0.5f, 0.1f, 0.8f); glEnd(); } if (bi->upOk()) { glBegin(GL_LINES); HEIGHT_VERTEX(0.5f, 0.1f, 0.8f); HEIGHT_VERTEX(0.5f, 0.1f, 0.2f); HEIGHT_VERTEX(0.45f, 0.1f, 0.3f); HEIGHT_VERTEX(0.5f, 0.1f, 0.2f); HEIGHT_VERTEX(0.55f, 0.1f, 0.3f); HEIGHT_VERTEX(0.5f, 0.1f, 0.2f); glEnd(); } if (bi->leftOk()) { glBegin(GL_LINES); HEIGHT_VERTEX(0.2f, 0.1f, 0.5f); HEIGHT_VERTEX(0.8f, 0.1f, 0.5f); HEIGHT_VERTEX(0.3f, 0.1f, 0.45f); HEIGHT_VERTEX(0.2f, 0.1f, 0.5f); HEIGHT_VERTEX(0.3f, 0.1f, 0.55f); HEIGHT_VERTEX(0.2f, 0.1f, 0.5f); glEnd(); } if (bi->rightOk()) { glBegin(GL_LINES); HEIGHT_VERTEX(0.8f, 0.1f, 0.5f); HEIGHT_VERTEX(0.2f, 0.1f, 0.5f); HEIGHT_VERTEX(0.7f, 0.1f, 0.45f); HEIGHT_VERTEX(0.8f, 0.1f, 0.5f); HEIGHT_VERTEX(0.7f, 0.1f, 0.55f); HEIGHT_VERTEX(0.8f, 0.1f, 0.5f); glEnd(); } // block lid normals //#if 0 glColor3f(1, 0, 0); #define NORMAL_POS(a, b) glVertex3f(a, slope_height_offset(which, a, b), b) #define NORMAL_POS2(a, b) glVertex3f(a + nx, slope_height_offset(which, a, b) + ny, b + nz) glBegin(GL_LINES); if (bi->lid) { NORMAL_POS(0.5f, 0.5f); NORMAL_POS2(0.5f, 0.5f); } glColor3f(0, 1, 0); if (bi->left) { glVertex3f(0, 0.5f, 0.5f); glVertex3f(-0.4f, 0.5f, 0.5f); } glColor3f(0, 0, 1); if (bi->right && !bi->isFlat()) { glVertex3f(1, 0.5f, 0.5f); glVertex3f(1.4f, 0.5f, 0.5f); } glColor3f(0, 1, 0); if (bi->top) { glVertex3f(0.5f, 0.5f, 0.0f); glVertex3f(0.5f, 0.5f, -0.4f); } glColor3f(0, 0, 1); if (bi->bottom && !bi->isFlat()) { glVertex3f(0.5f, 0.5f, 1.0f); glVertex3f(0.5f, 0.5f, 1.4f); } glEnd(); glColor3f(1, 1, 1); //#endif glEnable(GL_TEXTURE_2D); GL_CHECKERROR; } }