void FloatingTextRenderer::render(Camera* cam, Layer* layer, RenderList& instances) { if (!m_font) { //no font selected.. nothing to render return; } RenderList::const_iterator instance_it = instances.begin(); uint32_t lm = m_renderbackend->getLightingModel(); SDL_Color old_color = m_font->getColor(); if(m_font_color) { m_font->setColor(m_color.r, m_color.g, m_color.b, m_color.unused); } for (;instance_it != instances.end(); ++instance_it) { Instance* instance = (*instance_it)->instance; const std::string* saytext = instance->getSayText(); if (saytext) { const Rect& ir = (*instance_it)->dimensions; Image* img = m_font->getAsImageMultiline(*saytext); Rect r; r.x = (ir.x + ir.w/2) - img->getWidth()/2; /// the center of the text rect is always aligned to the instance's rect center. r.y = ir.y- img->getHeight(); /// make the text rect floating higher than the instance. r.w = img->getWidth(); r.h = img->getHeight(); // Without this check it can happen that changeRenderInfos() call produces an out_of_range error // because the image rendering can be skipped, if it's not on the screen. // The result is that it tried to modify more objects as exist. if (r.right() < 0 || r.x > static_cast<int32_t>(m_renderbackend->getWidth()) || r.bottom() < 0 || r.y > static_cast<int32_t>(m_renderbackend->getHeight())) { continue; } if(m_background || m_backborder) { const int32_t overdraw = 5; Point p = Point(r.x-overdraw, r.y-overdraw); if(m_background) { m_renderbackend->fillRectangle(p, r.w+2*overdraw, r.h+2*overdraw, m_backcolor.r, m_backcolor.g, m_backcolor.b, m_backcolor.unused); } if(m_backborder) { m_renderbackend->drawRectangle(p, r.w+2*overdraw, r.h+2*overdraw, m_backbordercolor.r, m_backbordercolor.g, m_backbordercolor.b, m_backbordercolor.unused); } } img->render(r); if(lm > 0) { uint16_t elements = 1; if (m_background) { ++elements; } if (m_backborder) { ++elements; } m_renderbackend->changeRenderInfos(RENDER_DATA_WITHOUT_Z, elements, 4, 5, false, true, 255, REPLACE, ALWAYS); } } } if(m_font_color) { m_font->setColor(old_color.r, old_color.g, old_color.b, old_color.unused); } }
bool Renderer::RemoveFromList(RenderableObject* obj, RenderList& renderlist){ for( RenderIterator it = renderlist.begin(); it != renderlist.end(); ++it ){ if( (*it) == obj ){ renderlist.erase(it); return true; } } return false; }
void FloatingTextRenderer::render(Camera* cam, Layer* layer, RenderList& instances) { if (!m_font) { //no font selected.. nothing to render return; } RenderList::const_iterator instance_it = instances.begin(); const std::string* saytext = NULL; uint32_t lm = m_renderbackend->getLightingModel(); SDL_Color old_color = m_font->getColor(); if(m_font_color) { m_font->setColor(m_color.r, m_color.g, m_color.b, m_color.unused); } for (;instance_it != instances.end(); ++instance_it) { Instance* instance = (*instance_it)->instance; saytext = instance->getSayText(); if (saytext) { const Rect& ir = (*instance_it)->dimensions; Image* img = m_font->getAsImageMultiline(*saytext); Rect r; r.x = (ir.x + ir.w/2) - img->getWidth()/2; /// the center of the text rect is always aligned to the instance's rect center. r.y = ir.y- img->getHeight(); /// make the text rect floating higher than the instance. r.w = img->getWidth(); r.h = img->getHeight(); if(m_background || m_backborder) { const int32_t overdraw = 5; Point p = Point(r.x-overdraw, r.y-overdraw); if(m_background) { m_renderbackend->fillRectangle(p, r.w+2*overdraw, r.h+2*overdraw, m_backcolor.r, m_backcolor.g, m_backcolor.b, m_backcolor.unused); } if(m_backborder) { m_renderbackend->drawRectangle(p, r.w+2*overdraw, r.h+2*overdraw, m_backbordercolor.r, m_backbordercolor.g, m_backbordercolor.b, m_backbordercolor.unused); } } img->render(r); if(lm > 0) { uint16_t elements = 1; if (m_background) { ++elements; } if (m_backborder) { ++elements; } m_renderbackend->changeRenderInfos(elements, 4, 5, false, true, 255, REPLACE, ALWAYS); } } } if(m_font_color) { m_font->setColor(old_color.r, old_color.g, old_color.b, old_color.unused); } }
void BlockingInfoRenderer::render(Camera* cam, Layer* layer, RenderList& instances) { CellGrid* cg = layer->getCellGrid(); if (!cg) { FL_WARN(_log, "No cellgrid assigned to layer, cannot draw grid"); return; } Rect cv = cam->getViewPort(); RenderList::const_iterator instance_it = instances.begin(); for (;instance_it != instances.end(); ++instance_it) { Instance* instance = (*instance_it)->instance; if (!instance->getObject()->isBlocking() || !instance->isBlocking()) { continue; } std::vector<ExactModelCoordinate> vertices; cg->getVertices(vertices, instance->getLocationRef().getLayerCoordinates()); std::vector<ExactModelCoordinate>::const_iterator it = vertices.begin(); int halfind = vertices.size() / 2; ScreenPoint firstpt = cam->toScreenCoordinates(cg->toMapCoordinates(*it)); Point pt1(firstpt.x, firstpt.y); Point pt2; ++it; for (; it != vertices.end(); it++) { ScreenPoint pts = cam->toScreenCoordinates(cg->toMapCoordinates(*it)); pt2.x = pts.x; pt2.y = pts.y; Point cpt1 = pt1; Point cpt2 = pt2; m_renderbackend->drawLine(cpt1, cpt2, m_color.r, m_color.g, m_color.b); pt1 = pt2; } m_renderbackend->drawLine(pt2, Point(firstpt.x, firstpt.y), m_color.r, m_color.g, m_color.b); ScreenPoint spt1 = cam->toScreenCoordinates(cg->toMapCoordinates(vertices[0])); Point pt3(spt1.x, spt1.y); ScreenPoint spt2 = cam->toScreenCoordinates(cg->toMapCoordinates(vertices[halfind])); Point pt4(spt2.x, spt2.y); m_renderbackend->drawLine(pt3, pt4, m_color.r, m_color.g, m_color.b); } }
void LayerCache::update(Camera::Transform transform, RenderList& renderlist) { const double OVERDRAW = 2.5; renderlist.clear(); m_needupdate = false; if(!m_layer->areInstancesVisible()) { FL_DBG(_log, "Layer instances hidden"); return; } bool isWarped = transform == Camera::WarpedTransform; if( isWarped ) { fullUpdate(); } Rect viewport = m_camera->getViewPort(); Rect screen_viewport = viewport; double zoom = m_camera->getZoom(); DoublePoint3D viewport_a = m_camera->screenToVirtualScreen(Point3D(viewport.x, viewport.y)); DoublePoint3D viewport_b = m_camera->screenToVirtualScreen(Point3D(viewport.right(), viewport.bottom())); viewport.x = static_cast<int32_t>(std::min(viewport_a.x, viewport_b.x)); viewport.y = static_cast<int32_t>(std::min(viewport_a.y, viewport_b.y)); viewport.w = static_cast<int32_t>(std::max(viewport_a.x, viewport_b.x) - viewport.x); viewport.h = static_cast<int32_t>(std::max(viewport_a.y, viewport_b.y) - viewport.y); uint8_t layer_trans = m_layer->getLayerTransparency(); double zmin = 0.0, zmax = 0.0; // FL_LOG(_log, LMsg("camera-update viewport") << viewport); std::vector<int32_t> index_list; collect(viewport, index_list); for(unsigned i=0; i!=index_list.size(); ++i) { Entry& entry = m_entries[index_list[i]]; // NOTE // An update is forced if the item has an animation/action. // This update only happens if it is _already_ included in the viewport // Nevertheless: Moving instances - which might move into the viewport will be updated // By the layer change listener. if(entry.force_update || !isWarped) { updateEntry(entry); } RenderItem& item = m_instances[entry.instance_index]; InstanceVisual* visual = item.instance->getVisual<InstanceVisual>(); bool visible = (visual->isVisible() != 0); uint8_t instance_trans = visual->getTransparency(); if(!item.image || !visible || (instance_trans == 255 && layer_trans == 0) || (instance_trans == 0 && layer_trans == 255)) { continue; } if(layer_trans != 0) { if(instance_trans != 0) { uint8_t calc_trans = layer_trans - instance_trans; if(calc_trans >= 0) { instance_trans = calc_trans; } else { instance_trans = 0; } } else { instance_trans = layer_trans; } } Point3D screen_point = m_camera->virtualScreenToScreen(item.screenpoint); // NOTE: // One would expect this to be necessary here, // however it works the same without, sofar // m_camera->calculateZValue(screen_point); // item.screenpoint.z = -screen_point.z; item.dimensions.x = screen_point.x; item.dimensions.y = screen_point.y; item.dimensions.w = item.bbox.w; item.dimensions.h = item.bbox.h; item.transparency = 255 - instance_trans; if (zoom != 1.0) { // NOTE: Due to image alignment, there is additional additions on image dimensions // There's probabaly some better solution for this, but works "good enough" for now. // In case additions are removed, gaps appear between tiles. item.dimensions.w = unsigned(double(item.bbox.w) * zoom + OVERDRAW); item.dimensions.h = unsigned(double(item.bbox.h) * zoom + OVERDRAW); } if (!m_need_sorting) { zmin = std::min(zmin, item.screenpoint.z); zmax = std::max(zmax, item.screenpoint.z); } if(item.dimensions.intersects(screen_viewport)) { renderlist.push_back(&item); } } if (m_need_sorting) { InstanceDistanceSort ids; std::stable_sort(renderlist.begin(), renderlist.end(), ids); } else { zmin -= 0.5; zmax += 0.5; // We want to put every z value in [-10,10] range. // To do it, we simply solve // { y1 = a*x1 + b // { y2 = a*x2 + b // where [y1,y2]' = [-10,10]' is required z range, // and [x1,x2]' is expected min,max z coords. double det = zmin - zmax; if (fabs(det) > FLT_EPSILON) { double det_a = -10.0 - 10.0; double det_b = 10.0 * zmin - (-10.0) * zmax; double a = static_cast<float>(det_a / det); double b = static_cast<float>(det_b / det); float estimate = sqrtf(static_cast<float>(renderlist.size())); float stack_delta = fabs(-10.0f - 10.0f) / estimate * 0.1f; RenderList::iterator it = renderlist.begin(); for ( ; it != renderlist.end(); ++it) { double& z = (*it)->screenpoint.z; z = a * z + b; InstanceVisual* vis = (*it)->instance->getVisual<InstanceVisual>(); z += vis->getStackPosition() * stack_delta; } } } // FL_LOG(_log, LMsg("camera-update ") << " N=" <<renderlist.size() << "/" << m_instances.size() << "/" << index_list.size()); }
void GameRenderer::renderWorld(GameWorld* world, const ViewCamera &camera, float alpha) { _renderAlpha = alpha; _renderWorld = world; // Store the input camera, _camera = camera; setupRender(); glBindVertexArray( vao ); float tod = world->getHour() + world->getMinute()/60.f; // Requires a float 0-24 auto weatherID = static_cast<WeatherLoader::WeatherCondition>(world->state->basic.nextWeather * 24); auto weather = world->data->weatherLoader.getWeatherData(weatherID, tod); glm::vec3 skyTop = weather.skyTopColor; glm::vec3 skyBottom = weather.skyBottomColor; glm::vec3 ambient = weather.ambientColor; glm::vec3 dynamic = weather.directLightColor; float theta = (tod/(60.f * 24.f) - 0.5f) * 2 * 3.14159265; glm::vec3 sunDirection{ sin(theta), 0.0, cos(theta), }; sunDirection = glm::normalize(sunDirection); _camera.frustum.near = world->state->cameraNear; _camera.frustum.far = weather.farClipping; auto view = _camera.getView(); auto proj = _camera.frustum.projection(); Renderer::SceneUniformData sceneParams { proj, view, glm::vec4{ambient, 0.0f}, glm::vec4{dynamic, 0.0f}, glm::vec4(skyBottom, 1.f), glm::vec4(camera.position, 0.f), weather.fogStart, camera.frustum.far }; renderer->setSceneParameters(sceneParams); renderer->clear(glm::vec4(skyBottom, 1.f)); _camera.frustum.update(proj * view); if (cullOverride) { cullingCamera.frustum.update( cullingCamera.frustum.projection() * cullingCamera.getView()); } culled = 0; renderer->useProgram(worldProg); //=============================================================== // Render List Construction //--------------------------------------------------------------- RW_PROFILE_BEGIN("RenderList"); // This is sequential at the moment, it should be easy to make it // run in parallel with a good threading system. RenderList renderList; // Naive optimisation, assume 10% hitrate renderList.reserve(world->allObjects.size() * 0.5f); RW_PROFILE_BEGIN("Build"); ObjectRenderer objectRenderer(_renderWorld, (cullOverride ? cullingCamera : _camera), _renderAlpha, getMissingTexture()); // World Objects for (auto object : world->allObjects) { objectRenderer.buildRenderList(object, renderList); } RW_PROFILE_END(); renderer->pushDebugGroup("Objects"); renderer->pushDebugGroup("RenderList"); // Also parallelizable RW_PROFILE_BEGIN("Sort"); std::sort(renderList.begin(), renderList.end(), [](const Renderer::RenderInstruction& a, const Renderer::RenderInstruction&b) { return a.sortKey < b.sortKey; }); RW_PROFILE_END(); RW_PROFILE_BEGIN("Draw"); renderer->drawBatched(renderList); RW_PROFILE_END(); renderer->popDebugGroup(); profObjects = renderer->popDebugGroup(); RW_PROFILE_END(); // Render arrows above anything that isn't radar only (or hidden) ModelRef& arrowModel = world->data->models["arrow"]; if( arrowModel && arrowModel->resource ) { auto arrowTex = world->data->textures[{"copblue",""}]; auto arrowFrame = arrowModel->resource->findFrame( "arrow" ); for( auto& blip : world->state->radarBlips ) { if( blip.second.display == BlipData::Show ) { glm::mat4 model; if( blip.second.target > 0 ) { // TODO restore arrows /*auto& pool = world->getTypeObjectPool(blip.second.target); auto object = pool.find(blip.second.target); if( object ) { model = object->getTimeAdjustedTransform( _renderAlpha ); }*/ } else { model = glm::translate( model, blip.second.coord ); } float a = world->getGameTime() * glm::pi<float>(); model = glm::translate( model, glm::vec3(0.f, 0.f, 2.5f + glm::sin( a ) * 0.5f) ); model = glm::rotate( model, a, glm::vec3(0.f, 0.f, 1.f) ); model = glm::scale( model, glm::vec3(1.5f, 1.5f, 1.5f) ); Renderer::DrawParameters dp; dp.textures = {arrowTex->getName()}; dp.ambient = 1.f; dp.colour = glm::u8vec4(255, 255, 255, 255); auto geom = arrowModel->resource->geometries[arrowFrame->getGeometries()[0]]; Model::SubGeometry& sg = geom->subgeom[0]; dp.start = sg.start; dp.count = sg.numIndices; dp.diffuse = 1.f; renderer->draw( model, &geom->dbuff, dp ); } } } // Draw goal indicators glDepthMask(GL_FALSE); renderer->useProgram( particleProg ); for(auto& i : world->getAreaIndicators()) { renderAreaIndicator( &i ); } glDepthMask(GL_TRUE); renderer->pushDebugGroup("Water"); water.render(this, world); profWater = renderer->popDebugGroup(); renderer->pushDebugGroup("Sky"); glBindVertexArray( vao ); Renderer::DrawParameters dp; dp.start = 0; dp.count = skydomeSegments * skydomeRows * 6; renderer->useProgram(skyProg); renderer->setUniform(skyProg, "TopColor", glm::vec4(skyTop, 1.f)); renderer->setUniform(skyProg, "BottomColor", glm::vec4(skyBottom, 1.f)); renderer->draw(glm::mat4(), &skyDbuff, dp); profSky = renderer->popDebugGroup(); renderer->pushDebugGroup("Effects"); renderEffects(world); profEffects = renderer->popDebugGroup(); glDisable(GL_DEPTH_TEST); GLuint splashTexName = 0; auto fc = world->state->fadeColour; if((fc.r + fc.g + fc.b) == 0 && world->state->currentSplash.size() > 0) { auto splash = world->data->findTexture(world->state->currentSplash); if ( splash ) { splashTexName = splash->getName(); } } if( (world->state->isCinematic || world->state->currentCutscene ) && splashTexName != 0 ) { renderLetterbox(); } float fadeTimer = world->getGameTime() - world->state->fadeStart; if( fadeTimer < world->state->fadeTime || !world->state->fadeOut ) { glUseProgram(ssRectProgram); glUniform2f(ssRectOffset, 0.f, 0.f); glUniform2f(ssRectSize, 1.f, 1.f); glUniform1i(ssRectTexture, 0); if(splashTexName != 0) { glBindTexture(GL_TEXTURE_2D, splashTexName); fc = glm::u16vec3(0, 0, 0); } else { glBindTexture(GL_TEXTURE_2D, 0); } float fadeFrac = 0.f; if( world->state->fadeTime > 0.f ) { fadeFrac = std::min(fadeTimer / world->state->fadeTime, 1.f); } float a = world->state->fadeOut ? 1.f - fadeFrac : fadeFrac; glm::vec4 fadeNormed(fc.r / 255.f, fc.g/ 255.f, fc.b/ 255.f, a); glUniform4fv(ssRectColour, 1, glm::value_ptr(fadeNormed)); glBindVertexArray( ssRectDraw.getVAOName() ); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } if( (world->state->isCinematic || world->state->currentCutscene ) && splashTexName == 0 ) { renderLetterbox(); } renderPostProcess(); glUseProgram(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray( 0 ); }
void Graphics::Plot(HDC hdc, RenderList& renderList) { for (RenderList::iterator ite = renderList.begin(); ite != renderList.end(); ++ite) { if (!ite->TestState(TriangleStateInactive) && !ite->TestState(TriangleStateBackface) && !ite->TestState(TriangleStateClipped)) PlotTriangle(hdc, *ite); } }