diff --git a/source/glest_game/graphics/renderer.cpp b/source/glest_game/graphics/renderer.cpp index 7630bebd..d961c131 100644 --- a/source/glest_game/graphics/renderer.cpp +++ b/source/glest_game/graphics/renderer.cpp @@ -1061,6 +1061,7 @@ static Vec2i _unprojectMap(const Vec2i& pt,const GLdouble* model,const GLdouble* // return ( translation * orientation ); //} + bool Renderer::ExtractFrustum(VisibleQuadContainerCache &quadCacheItem) { bool frustrumChanged = false; vector proj(16,0); @@ -1297,6 +1298,20 @@ bool Renderer::PointInFrustum(vector > &frustum, float x, float y, return true; } +bool Renderer::SphereInFrustum(vector > &frustum, float x, float y, float z, float radius) { + // Go through all the sides of the frustum + for(int i = 0; i < frustum.size(); i++ ) { + // If the center of the sphere is farther away from the plane than the radius + if(frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] <= -radius ) { + // The distance was greater than the radius so the sphere is outside of the frustum + return false; + } + } + + // The sphere was inside of the frustum! + return true; +} + bool Renderer::CubeInFrustum(vector > &frustum, float x, float y, float z, float size ) { unsigned int p=0; @@ -5744,63 +5759,256 @@ Vec3f Renderer::computeScreenPosition(const Vec3f &worldPos) { return screenPos; } -void Renderer::computeSelected( Selection::UnitContainer &units, const Object *&obj, const bool withObjectSelection, +void Renderer::computeSelected( Selection::UnitContainer &units, const Object *&obj, + const bool withObjectSelection, const Vec2i &posDown, const Vec2i &posUp) { - //declarations - GLuint selectBuffer[Gui::maxSelBuff]; const Metrics &metrics= Metrics::getInstance(); //compute center and dimensions of selection rectangle - int x= (posDown.x+posUp.x) / 2; - int y= (posDown.y+posUp.y) / 2; - int w= abs(posDown.x-posUp.x); - int h= abs(posDown.y-posUp.y); - if(w<1) w=1; - if(h<1) h=1; - - //setup matrices - glSelectBuffer(Gui::maxSelBuff, selectBuffer); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()}; - glRenderMode(GL_SELECT); - glLoadIdentity(); - gluPickMatrix(x, y, w, h, view); - gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane); - loadGameCameraMatrix(); - - //render units to find which ones should be selected - renderUnitsFast(); - if(withObjectSelection){ - renderObjectsFast(false,true); + int x = (posDown.x+posUp.x) / 2; + int y = (posDown.y+posUp.y) / 2; + int w = abs(posDown.x-posUp.x); + int h = abs(posDown.y-posUp.y); + if(w < 1) { + w = 1; + } + if(h < 1) { + h = 1; } - //pop matrices - glMatrixMode(GL_PROJECTION); - glPopMatrix(); + const bool newPickingSelection = Config::getInstance().getBool("EnableColorPicking","true"); + if(newPickingSelection == true) { + int x1 = posDown.x; + int y1 = posDown.y; + int x2 = posUp.x; + int y2 = posUp.y; + + x = min(x1,x2); + y = min(y1,y2); + w = max(x1,x2) - min(x1,x2); + h = max(y1,y2) - min(y1,y2); + if(w < 1) { + w = 1; + } + if(h < 1) { + h = 1; + } + + x= (x * metrics.getScreenW() / metrics.getVirtualW()); + y= (y * metrics.getScreenH() / metrics.getVirtualH()); + + w= (w * metrics.getScreenW() / metrics.getVirtualW()); + h= (h * metrics.getScreenH() / metrics.getVirtualH()); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + //GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()}; + //gluPickMatrix(x, y, w, h, view); + gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane); + loadGameCameraMatrix(); + + //render units to find which ones should be selected + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + vector rendererUnits = renderUnitsFast(false, newPickingSelection); + + //printf("In [%s::%s] Line: %d rendererUnits = %d\n",__FILE__,__FUNCTION__,__LINE__,rendererUnits.size()); + + vector rendererObjects; + if(withObjectSelection == true) { + rendererObjects = renderObjectsFast(false,true,newPickingSelection); + } + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //pop matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + // Added this to ensure all the selection calls are done now + // (see http://www.unknownroad.com/rtfm/graphics/glselection.html section: [0x4]) + glFlush(); + + //GraphicsInterface::getInstance().getCurrentContext()->swapBuffers(); + + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + vector rendererModels; + for(unsigned int i = 0; i < rendererObjects.size(); ++i) { + Object *object = rendererObjects[i]; + rendererModels.push_back(object); + //printf("In [%s::%s] Line: %d rendered object i = %d [%s] [%s]\n",__FILE__,__FUNCTION__,__LINE__,i,object->getUniquePickName().c_str(),object->getColorDescription().c_str()); + + //printf("In [%s::%s] Line: %d\ni = %d [%d - %s] ptr[%p] color[%s]\n",__FILE__,__FUNCTION__,__LINE__,i,unit->getId(),unit->getType()->getName().c_str(),unit->getCurrentModelPtr(),unit->getColorDescription().c_str()); + } + + //printf("In [%s::%s] Line: %d\nLooking for picks inside [%d,%d,%d,%d] posdown [%s] posUp [%s]",__FILE__,__FUNCTION__,__LINE__,x,y,w,h,posDown.getString().c_str(),posUp.getString().c_str()); + //select units by checking the selected buffer + //vector rendererModels; + for(unsigned int i = 0; i < rendererUnits.size(); ++i) { + Unit *unit = rendererUnits[i]; + rendererModels.push_back(unit); + //printf("In [%s::%s] Line: %d rendered unit i = %d [%s] [%s]\n",__FILE__,__FUNCTION__,__LINE__,i,unit->getUniquePickName().c_str(),unit->getColorDescription().c_str()); + + //printf("In [%s::%s] Line: %d\ni = %d [%d - %s] ptr[%p] color[%s]\n",__FILE__,__FUNCTION__,__LINE__,i,unit->getId(),unit->getType()->getName().c_str(),unit->getCurrentModelPtr(),unit->getColorDescription().c_str()); + } + //printf("In [%s::%s] Line: %d\nLooking for picks inside [%d,%d,%d,%d] posdown [%s] posUp [%s]",__FILE__,__FUNCTION__,__LINE__,x,y,w,h,posDown.getString().c_str(),posUp.getString().c_str()); + + //vector pickedList = BaseColorPickEntity::getPickedList(x,y,w,h, rendererModels); + + vector pickedList = BaseColorPickEntity::getPickedList(x,y,w,h, rendererModels); + //printf("In [%s::%s] Line: %d pickedList = %d models rendered = %d\n",__FILE__,__FUNCTION__,__LINE__,pickedList.size(),rendererModels.size()); + + if(pickedList.empty() == false) { + for(int i = 0; i < pickedList.size(); ++i) { + int index = pickedList[i]; + + //printf("In [%s::%s] Line: %d searching for selected object i = %d index = %d units = %d objects = %d\n",__FILE__,__FUNCTION__,__LINE__,i,index,rendererUnits.size(),rendererObjects.size()); + + if(rendererObjects.size() > 0 && index < rendererObjects.size()) { + Object *object = rendererObjects[index]; + //printf("In [%s::%s] Line: %d searching for selected object i = %d index = %d [%p]\n",__FILE__,__FUNCTION__,__LINE__,i,index,object); + + if(object != NULL) { + obj = object; + if(withObjectSelection == true) { + //printf("In [%s::%s] Line: %d found selected object [%p]\n",__FILE__,__FUNCTION__,__LINE__,obj); + return; + } + } + } + else { + index -= rendererObjects.size(); + Unit *unit = rendererUnits[index]; + if(unit != NULL && unit->isAlive()) { + units.push_back(unit); + } + + } + } + } + + + +// vector pickedList = BaseColorPickEntity::getPickedList(x,y,w,h, rendererModels); +// //printf("In [%s::%s] Line: %d pickedList = %d\n",__FILE__,__FUNCTION__,__LINE__,pickedList.size()); +// +// if(pickedList.empty() == false) { +// for(int i = 0; i < pickedList.size(); ++i) { +// int index = pickedList[i]; +// Unit *unit = rendererUnits[index]; +// if(unit != NULL && unit->isAlive()) { +// units.push_back(unit); +// } +// } +// } + + //printf("In [%s::%s] Line: %d units = %d\n",__FILE__,__FUNCTION__,__LINE__,units.size()); + + +/* Frustrum approach --> Currently not accurate enough + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()}; + gluPickMatrix(x, y, w, h, view); + gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane); + loadGameCameraMatrix(); + + VisibleQuadContainerCache quadSelectionCacheItem; + ExtractFrustum(quadSelectionCacheItem); + + //pop matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); - //select units by checking the selected buffer - int selCount= glRenderMode(GL_RENDER); - if(selCount > 0) { VisibleQuadContainerCache &qCache = getQuadCache(); - for(int i=1; i <= selCount; ++i) { - int index= selectBuffer[i*4-1]; - if(index>=OBJECT_SELECT_OFFSET) - { - Object *object = qCache.visibleObjectList[index-OBJECT_SELECT_OFFSET]; - if(object != NULL) { - obj=object; - if(withObjectSelection) { - break; + if(qCache.visibleQuadUnitList.empty() == false) { + for(int visibleUnitIndex = 0; + visibleUnitIndex < qCache.visibleQuadUnitList.size(); ++visibleUnitIndex) { + Unit *unit = qCache.visibleQuadUnitList[visibleUnitIndex]; + if(unit != NULL && unit->isAlive()) { + Vec3f unitPos = unit->getCurrVector(); + bool insideQuad = CubeInFrustum(quadSelectionCacheItem.frustumData, + unitPos.x, unitPos.y, unitPos.z, unit->getType()->getSize()); + if(insideQuad == true) { + units.push_back(unit); } } } - else - { - Unit *unit = qCache.visibleQuadUnitList[index]; - if(unit != NULL && unit->isAlive()) { - units.push_back(unit); + } + + if(withObjectSelection == true) { + if(qCache.visibleObjectList.empty() == false) { + for(int visibleIndex = 0; + visibleIndex < qCache.visibleObjectList.size(); ++visibleIndex) { + Object *object = qCache.visibleObjectList[visibleIndex]; + if(object != NULL) { + bool insideQuad = CubeInFrustum(quadSelectionCacheItem.frustumData, + object->getPos().x, object->getPos().y, object->getPos().z, 1); + if(insideQuad == true) { + obj = object; + if(withObjectSelection == true) { + break; + } + } + } + } + } + } +*/ + + } + else { + //declarations + GLuint selectBuffer[Gui::maxSelBuff]; + + //setup matrices + glSelectBuffer(Gui::maxSelBuff, selectBuffer); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + GLint view[]= {0, 0, metrics.getVirtualW(), metrics.getVirtualH()}; + glRenderMode(GL_SELECT); + glLoadIdentity(); + gluPickMatrix(x, y, w, h, view); + gluPerspective(perspFov, metrics.getAspectRatio(), perspNearPlane, perspFarPlane); + loadGameCameraMatrix(); + + //render units to find which ones should be selected + renderUnitsFast(); + if(withObjectSelection == true) { + renderObjectsFast(false,true); + } + + //pop matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + // Added this to ensure all the selection calls are done now + // (see http://www.unknownroad.com/rtfm/graphics/glselection.html section: [0x4]) + glFlush(); + + //select units by checking the selected buffer + int selCount= glRenderMode(GL_RENDER); + if(selCount > 0) { + VisibleQuadContainerCache &qCache = getQuadCache(); + for(int i = 1; i <= selCount; ++i) { + int index = selectBuffer[i*4-1]; + if(index >= OBJECT_SELECT_OFFSET) { + Object *object = qCache.visibleObjectList[index - OBJECT_SELECT_OFFSET]; + if(object != NULL) { + obj = object; + if(withObjectSelection == true) { + break; + } + } + } + else { + Unit *unit = qCache.visibleQuadUnitList[index]; + if(unit != NULL && unit->isAlive()) { + units.push_back(unit); + } } } } @@ -6268,16 +6476,17 @@ Vec4f Renderer::computeWaterColor(float waterLevel, float cellHeight) { // ==================== fast render ==================== //render units for selection purposes -void Renderer::renderUnitsFast(bool renderingShadows) { +vector Renderer::renderUnitsFast(bool renderingShadows, bool colorPickingSelection) { + vector unitsList; if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) { - return; + return unitsList; } assert(game != NULL); const World *world= game->getWorld(); assert(world != NULL); - assertGl(); + //assertGl(); bool modelRenderStarted = false; VisibleQuadContainerCache &qCache = getQuadCache(); @@ -6288,35 +6497,54 @@ void Renderer::renderUnitsFast(bool renderingShadows) { if(modelRenderStarted == false) { modelRenderStarted = true; - //glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); - glDisable(GL_LIGHTING); - if (renderingShadows == false) { - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_TEXTURE_2D); + + if(colorPickingSelection == false) { + //glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); + glDisable(GL_LIGHTING); + if (renderingShadows == false) { + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + } + else { + glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); + glEnable(GL_TEXTURE_2D); + glAlphaFunc(GL_GREATER, 0.4f); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + //set color to the texture alpha + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + + //set alpha to the texture alpha + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + } } - else { - glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); - glEnable(GL_TEXTURE_2D); - glAlphaFunc(GL_GREATER, 0.4f); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - //set color to the texture alpha - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - - //set alpha to the texture alpha - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - } + //assertGl(); modelRenderer->begin(false, renderingShadows, false); - glInitNames(); + + //assertGl(); + + if(colorPickingSelection == true) { + BaseColorPickEntity::beginPicking(); + } + else { + glInitNames(); + } + + //assertGl(); } - glPushName(visibleUnitIndex); + if(colorPickingSelection == false) { + glPushName(visibleUnitIndex); + } + + //assertGl(); glMatrixMode(GL_MODELVIEW); //debuxar modelo @@ -6332,25 +6560,55 @@ void Renderer::renderUnitsFast(bool renderingShadows) { //render Model *model= unit->getCurrentModelPtr(); model->updateInterpolationVertices(unit->getAnimProgress(), unit->isAlive() && !unit->isAnimProgressBound()); + + if(colorPickingSelection == true) { + unit->setUniquePickingColor(); + unitsList.push_back(unit); + + //assertGl(); + } + + //assertGl(); + modelRenderer->render(model); glPopMatrix(); - glPopName(); + + if(colorPickingSelection == false) { + glPopName(); + } + + //assertGl(); } if(modelRenderStarted == true) { + //assertGl(); + modelRenderer->end(); - glPopAttrib(); + + //assertGl(); + + if(colorPickingSelection == true) { + BaseColorPickEntity::endPicking(); + } + else { + glPopAttrib(); + } + +// assertGl(); } } - assertGl(); +// assertGl(); + + return unitsList; } //render objects for selection purposes -void Renderer::renderObjectsFast(bool renderingShadows, bool resourceOnly) { +vector Renderer::renderObjectsFast(bool renderingShadows, bool resourceOnly, bool colorPickingSelection) { + vector objectList; if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) { - return; + return objectList; } //const World *world= game->getWorld(); @@ -6370,54 +6628,86 @@ void Renderer::renderObjectsFast(bool renderingShadows, bool resourceOnly) { if(modelRenderStarted == false) { modelRenderStarted = true; - glDisable(GL_LIGHTING); + if(colorPickingSelection == false) { + glDisable(GL_LIGHTING); - if (renderingShadows == false){ - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_TEXTURE_2D); + if (renderingShadows == false){ + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_TEXTURE_2D); + } + else { + glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); + glAlphaFunc(GL_GREATER, 0.5f); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + //set color to the texture alpha + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + + //set alpha to the texture alpha + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + } + } + + modelRenderer->begin(false, renderingShadows, false); + + if(colorPickingSelection == true) { + BaseColorPickEntity::beginPicking(); } else { - glPushAttrib(GL_ENABLE_BIT| GL_TEXTURE_BIT); - glAlphaFunc(GL_GREATER, 0.5f); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - //set color to the texture alpha - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - - //set alpha to the texture alpha - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glInitNames(); } - modelRenderer->begin(false, renderingShadows, false); - glInitNames(); } - if(!resourceOnly || o->getResource()!= NULL){ + + if(resourceOnly == false || o->getResource()!= NULL) { Model *objModel= o->getModelPtr(); const Vec3f &v= o->getConstPos(); - glPushName(OBJECT_SELECT_OFFSET+visibleIndex); + + if(colorPickingSelection == false) { + glPushName(OBJECT_SELECT_OFFSET+visibleIndex); + } + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(v.x, v.y, v.z); glRotatef(o->getRotation(), 0.f, 1.f, 0.f); + if(colorPickingSelection == true) { + o->setUniquePickingColor(); + objectList.push_back(o); + + //assertGl(); + } + modelRenderer->render(objModel); glPopMatrix(); - glPopName(); + + if(colorPickingSelection == false) { + glPopName(); + } } } if(modelRenderStarted == true) { modelRenderer->end(); - glPopAttrib(); + + if(colorPickingSelection == true) { + BaseColorPickEntity::endPicking(); + } + else { + glPopAttrib(); + } } } assertGl(); + + return objectList; } // ==================== gl caps ==================== diff --git a/source/glest_game/graphics/renderer.h b/source/glest_game/graphics/renderer.h index 1bee25d4..7874a841 100644 --- a/source/glest_game/graphics/renderer.h +++ b/source/glest_game/graphics/renderer.h @@ -249,6 +249,7 @@ private: Quad2i visibleQuadFromCamera; Vec4f nearestLightPos; VisibleQuadContainerCache quadCache; + VisibleQuadContainerCache quadCacheSelection; //renderers ModelRenderer *modelRenderer; @@ -370,6 +371,7 @@ private: bool ExtractFrustum(VisibleQuadContainerCache &quadCacheItem); bool PointInFrustum(vector > &frustum, float x, float y, float z ); + bool SphereInFrustum(vector > &frustum, float x, float y, float z, float radius); bool CubeInFrustum(vector > &frustum, float x, float y, float z, float size ); private: @@ -580,8 +582,8 @@ private: void checkExtension(const string &extension, const string &msg); //selection render - void renderObjectsFast(bool renderingShadows = false, bool resourceOnly = false); - void renderUnitsFast(bool renderingShadows = false); + vector renderObjectsFast(bool renderingShadows = false, bool resourceOnly = false, bool colorPickingSelection = false); + vector renderUnitsFast(bool renderingShadows = false, bool colorPickingSelection = false); //gl requirements void checkGlCaps(); diff --git a/source/glest_game/type_instances/object.cpp b/source/glest_game/type_instances/object.cpp index 803e84d6..dca34957 100644 --- a/source/glest_game/type_instances/object.cpp +++ b/source/glest_game/type_instances/object.cpp @@ -33,7 +33,7 @@ ObjectStateInterface *Object::stateCallback=NULL; // class Object // ===================================================== -Object::Object(ObjectType *objectType, const Vec3f &pos, const Vec2i &mapPos) { +Object::Object(ObjectType *objectType, const Vec3f &pos, const Vec2i &mapPos) : BaseColorPickEntity() { RandomGen random; random.init(static_cast(pos.x*pos.z)); @@ -172,4 +172,13 @@ void Object::setVisible( bool visible) } } +string Object::getUniquePickName() const { + string result = ""; + if(resource != NULL) { + result += resource->getDescription() + " : "; + } + result += mapPos.getString(); + return result; +} + }}//end namespace diff --git a/source/glest_game/type_instances/object.h b/source/glest_game/type_instances/object.h index 89fec505..3d475a04 100644 --- a/source/glest_game/type_instances/object.h +++ b/source/glest_game/type_instances/object.h @@ -42,7 +42,7 @@ public: virtual void removingObjectEvent(Object *object) = 0; }; -class Object { +class Object : public BaseColorPickEntity { private: typedef vector UnitParticleSystems; @@ -86,6 +86,8 @@ public: void setLastRenderFrame(int value) { lastRenderFrame = value; } const Vec2i & getMapPos() const { return mapPos; } + + virtual string getUniquePickName() const; }; }}//end namespace diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 39c69dfb..f7c09ff3 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -284,7 +284,8 @@ const int Unit::invalidId= -1; Game *Unit::game = NULL; -Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType *type, Faction *faction, Map *map, CardinalDir placeFacing):id(id) { +Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, + const UnitType *type, Faction *faction, Map *map, CardinalDir placeFacing) : BaseColorPickEntity(), id(id) { #ifdef LEAK_CHECK_UNITS Unit::mapMemoryList[this]=true; #endif @@ -3245,6 +3246,12 @@ Vec2i Unit::getPosWithCellMapSet() const { return cellMapPos; } +string Unit::getUniquePickName() const { + string result = intToStr(id) + " - " + type->getName() + " : "; + result += pos.getString(); + return result; +} + std::string Unit::toString() const { std::string result = ""; diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index 8741a9cc..5b1a7a77 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -277,7 +277,7 @@ public: UnitAttackBoostEffect *currentAppliedEffect; }; -class Unit : public ValueCheckerVault { +class Unit : public BaseColorPickEntity, ValueCheckerVault { private: typedef list Commands; typedef list Observers; @@ -625,6 +625,8 @@ public: void setUsePathfinderExtendedMaxNodes(bool value) { usePathfinderExtendedMaxNodes = value; } void updateTimedParticles(); + + virtual string getUniquePickName() const; private: float computeHeight(const Vec2i &pos) const; void calculateXZRotation(); diff --git a/source/shared_lib/include/graphics/model.h b/source/shared_lib/include/graphics/model.h index 203af5c0..f0e5556e 100644 --- a/source/shared_lib/include/graphics/model.h +++ b/source/shared_lib/include/graphics/model.h @@ -216,6 +216,31 @@ private: void buildInterpolationData() const; }; +class BaseColorPickEntity { +private: + static const int COLOR_COMPONENTS = 3; + unsigned char uniqueColorID[COLOR_COMPONENTS]; + + static unsigned char nextColorID[COLOR_COMPONENTS]; + static Mutex mutexNextColorID; + +public: + + BaseColorPickEntity(); + static void beginPicking(); + static void endPicking(); + static vector getPickedList(int x,int y,int w,int h, const vector &rendererModels); + + void setUniquePickingColor() const; + bool isUniquePickingColor(unsigned char *pixel) const; + + string getColorDescription() const; + virtual string getUniquePickName() const = 0; + + ~BaseColorPickEntity() {}; +}; + + }}//end namespace #endif diff --git a/source/shared_lib/include/platform/common/platform_common.h b/source/shared_lib/include/platform/common/platform_common.h index 21e9ce0c..c4e0ad9d 100644 --- a/source/shared_lib/include/platform/common/platform_common.h +++ b/source/shared_lib/include/platform/common/platform_common.h @@ -119,9 +119,10 @@ private: bool lastStopped; public: - Chrono(); + Chrono(bool autoStart=false); void start(); void stop(); + void reset(); int64 getMicros(); int64 getMillis(); int64 getSeconds(); diff --git a/source/shared_lib/sources/graphics/model.cpp b/source/shared_lib/sources/graphics/model.cpp index b670e71d..14fa34ed 100644 --- a/source/shared_lib/sources/graphics/model.cpp +++ b/source/shared_lib/sources/graphics/model.cpp @@ -21,6 +21,7 @@ #include "platform_common.h" #include "opengl.h" #include "platform_util.h" +#include #include "leak_dumper.h" using namespace Shared::Platform; @@ -34,8 +35,6 @@ namespace Shared{ namespace Graphics{ using namespace Util; -//bool Model::masterserverMode = false; - // ===================================================== // class Mesh // ===================================================== @@ -960,4 +959,225 @@ void Model::deletePixels() { } } + +//unsigned char BaseColorPickEntity::nextColorID[COLOR_COMPONENTS] = {1, 1, 1, 1}; +unsigned char BaseColorPickEntity::nextColorID[COLOR_COMPONENTS] = { 1, 1, 1 }; +Mutex BaseColorPickEntity::mutexNextColorID; + +BaseColorPickEntity::BaseColorPickEntity() { + MutexSafeWrapper safeMutex(&mutexNextColorID); + + uniqueColorID[0] = nextColorID[0]; + uniqueColorID[1] = nextColorID[1]; + uniqueColorID[2] = nextColorID[2]; + //uniqueColorID[3] = nextColorID[3]; + + const int colorSpacing = 2; + + if(nextColorID[0] + colorSpacing <= 255) { + nextColorID[0] += colorSpacing; + } + else { + nextColorID[0] = 1; + if(nextColorID[1] + colorSpacing <= 255) { + nextColorID[1] += colorSpacing; + } + else { + nextColorID[1] = 1; + if(nextColorID[2] + colorSpacing <= 255) { + nextColorID[2] += colorSpacing; + } + else { + + //printf("Color rolled over on 3rd level!\n"); + + nextColorID[0] = 1; + nextColorID[1] = 1; + nextColorID[2] = 1; + + +// nextColorID[2] = 1; +// nextColorID[3]+=colorSpacing; +// +// if(nextColorID[3] > 255) { +// nextColorID[0] = 1; +// nextColorID[1] = 1; +// nextColorID[2] = 1; +// nextColorID[3] = 1; +// } + } + } + } +} + +string BaseColorPickEntity::getColorDescription() const { + string result = ""; + char szBuf[100]=""; + //sprintf(szBuf,"%d.%d.%d.%d",uniqueColorID[0],uniqueColorID[1],uniqueColorID[2],uniqueColorID[3]); + sprintf(szBuf,"%d.%d.%d",uniqueColorID[0],uniqueColorID[1],uniqueColorID[2]); + result = szBuf; + return result; +} + +void BaseColorPickEntity::beginPicking() { + // turn off texturing, lighting and fog + //glClearColor (0.0,0.0,0.0,0.0); + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_FOG); + glDisable(GL_LIGHTING); + + glDisable(GL_BLEND); + glDisable(GL_MULTISAMPLE); + glDisable(GL_DITHER); + + //glDisable(GL_LIGHT0); + //glDisable(GL_LIGHT1); + //glDisable(GL_LIGHT2); + //glDisable(GL_LIGHT3); + //glDisable(GL_LIGHT4); + //glDisable(GL_LIGHT5); + //glDisable(GL_LIGHT6); + //glDisable(GL_LIGHT7); + + //glDisable(GL_ALPHA_TEST); + //glDisable(GL_COLOR_MATERIAL); + + //glDisable(GL_DEPTH_TEST); + //glDisable(GL_TEXTURE_GEN_S); + //glDisable(GL_TEXTURE_GEN_T); + //glDisable(GL_TEXTURE_GEN_R); + //glDisable(GL_TEXTURE_GEN_Q); + +} + +void BaseColorPickEntity::endPicking() { + // turn off texturing, lighting and fog + + glEnable(GL_TEXTURE_2D); + glEnable(GL_FOG); + glEnable(GL_LIGHTING); + + glEnable(GL_BLEND); + glEnable(GL_MULTISAMPLE); + glEnable(GL_DITHER); + + //glEnable(GL_TEXTURE_2D); + //glEnable(GL_FOG); + //glEnable(GL_LIGHTING); + + //glEnable(GL_BLEND); + //glEnable(GL_MULTISAMPLE); + //glEnable(GL_DITHER); +} + +vector BaseColorPickEntity::getPickedList(int x,int y,int w,int h, const vector &rendererModels) { + vector pickedModels; + + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //Pixmap2D *pixmapScreenShot = new Pixmap2D(w+1, h+1, COLOR_COMPONENTS); + static auto_ptr cachedPixels; + static int cachedPixelsW = -1; + static int cachedPixelsH = -1; + unsigned char *pixelBuffer = NULL; + + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + static Chrono lastSnapshot(true); + + // Only update the pixel buffer every 350 milliseconds or as required + if(cachedPixels.get() == NULL || cachedPixelsW != w+1 || cachedPixelsH != h+1 || + lastSnapshot.getMillis() > 350) { + //printf("Updating selection millis = %ld\n",lastSnapshot.getMillis()); + + lastSnapshot.reset(); + + Pixmap2D *pixmapScreenShot = new Pixmap2D(w+1, h+1, COLOR_COMPONENTS); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(x, y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels()); + //glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels()); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + cachedPixels.reset(new unsigned char[pixmapScreenShot->getPixelByteCount()]); + memcpy(cachedPixels.get(),pixmapScreenShot->getPixels(),pixmapScreenShot->getPixelByteCount()); + cachedPixelsW = w+1; + cachedPixelsH = h+1; + + delete pixmapScreenShot; + } + pixelBuffer = cachedPixels.get(); + + // Enable screenshots to debug selection scene + //pixmapScreenShot->save("debug.png"); + + //printf("In [%s::%s] Line: %d x,y,w,h [%d,%d,%d,%d] pixels = %d\n",__FILE__,__FUNCTION__,__LINE__,x,y,w,h,pixmapScreenShot->getPixelByteCount()); + + // now our picked screen pixel color is stored in pixel[3] + // so we search through our object list looking for the object that was selected + + map modelAlreadyPickedList; + map > > colorAlreadyPickedList; + int nEnd = w * h; + for(int x = 0; x < nEnd && pickedModels.size() < rendererModels.size(); ++x) { + int index = x * COLOR_COMPONENTS; + unsigned char *pixel = &pixelBuffer[index]; + + // Skip duplicate scanned colors + map > >::iterator iterFind1 = colorAlreadyPickedList.find(pixel[0]); + if(iterFind1 != colorAlreadyPickedList.end()) { + map >::iterator iterFind2 = iterFind1->second.find(pixel[1]); + if(iterFind2 != iterFind1->second.end()) { + map::iterator iterFind3 = iterFind2->second.find(pixel[2]); + if(iterFind3 != iterFind2->second.end()) { + continue; + } + } + } + + for(unsigned int i = 0; i < rendererModels.size(); ++i) { + // Skip models already selected + if(modelAlreadyPickedList.find(i) != modelAlreadyPickedList.end()) { + continue; + } + const BaseColorPickEntity *model = rendererModels[i]; + + if( model != NULL && model->isUniquePickingColor(pixel) == true) { + //printf("Found match pixel [%d.%d.%d] for model [%s] ptr [%p][%s]\n",pixel[0],pixel[1],pixel[2],model->getColorDescription().c_str(), model,model->getUniquePickName().c_str()); + + pickedModels.push_back(i); + modelAlreadyPickedList[i]=true; + colorAlreadyPickedList[pixel[0]][pixel[1]][pixel[2]]=true; + break; + } + } + } + + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //delete pixmapScreenShot; + + //printf("In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + return pickedModels; +} + +bool BaseColorPickEntity::isUniquePickingColor(unsigned char *pixel) const { + bool result = false; + if( uniqueColorID[0] == pixel[0] && + uniqueColorID[1] == pixel[1] && + uniqueColorID[2] == pixel[2]) { + //uniqueColorID[3] == pixel[3]) { + result = true; + } + + return result; +} + +void BaseColorPickEntity::setUniquePickingColor() const { + glColor3f( uniqueColorID[0] / 255.0f, + uniqueColorID[1] / 255.0f, + uniqueColorID[2] / 255.0f); + //uniqueColorID[3] / 255.0f); +} + + }}//end namespace diff --git a/source/shared_lib/sources/platform/common/platform_common.cpp b/source/shared_lib/sources/platform/common/platform_common.cpp index 555ebfb6..9ed0f029 100644 --- a/source/shared_lib/sources/platform/common/platform_common.cpp +++ b/source/shared_lib/sources/platform/common/platform_common.cpp @@ -116,7 +116,7 @@ void PerformanceTimer::reset(){ // Chrono // ===================================== -Chrono::Chrono() { +Chrono::Chrono(bool autoStart) { freq = 1000; stopped= true; accumCount= 0; @@ -126,6 +126,10 @@ Chrono::Chrono() { lastResult = 0; lastMultiplier = 0; lastStopped = false; + + if(autoStart == true) { + start(); + } } void Chrono::start() { @@ -140,6 +144,16 @@ void Chrono::stop() { stopped= true; } +void Chrono::reset() { + accumCount = 0; + lastStartCount = 0; + lastTickCount = 0; + lastResult = 0; + lastMultiplier = 0; + + startCount = SDL_GetTicks(); +} + int64 Chrono::getMicros() { return queryCounter(1000000); }