void UIEnd() { ui_draw2d.End(); ui_draw2d_front.End(); ui_draw2d.Flush(); ui_draw2d_front.Flush(); }
void UIInit(const Atlas *atlas, const UITheme &ui_theme) { ui_draw2d.SetAtlas(atlas); ui_draw2d_front.SetAtlas(atlas); themeAtlas = atlas; theme = ui_theme; memset(&uistate, 0, sizeof(uistate)); }
// TODO int UIHSlider(int id, int x, int y, int w, int max, int *value) { // Calculate mouse cursor's relative y offset int xpos = ((256 - 16) * *value) / max; for (int i = 0; i < MAX_POINTERS; i++) { // Check for hotness if (UIRegionHit(i, x+8, y+8, 16, 255, 0)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) uistate.activeitem[i] = id; } // Update widget value if (uistate.activeitem[i] == id) { int mousepos = uistate.mousey[i] - (y + 8); if (mousepos < 0) mousepos = 0; if (mousepos > 255) mousepos = 255; int v = (mousepos * max) / 255; if (v != *value) { *value = v; return 1; } } } // Render the scrollbar ui_draw2d.Rect(x, y, 32, 256+16, 0x777777); ui_draw2d.Rect(x+8+xpos, y+8, 16, 16, 0xffffff); return 0; }
//------------------------------------------------------ void DrawSheet::_removeDrawOperation(DrawOperation* toRemove) { DrawBuffer* buf = getBufferForOperation(toRemove); if (buf) buf->removeDrawOperation(toRemove); mDrawOpMap.erase(toRemove->getID()); }
void UIText(int font, const LayoutManager &layout, const char *text, uint32_t color, float scale, int align) { ui_draw2d.SetFontScale(scale, scale); float w, h; ui_draw2d.MeasureText(font, text, &w, &h); float x, y; layout.GetPos(&w, &h, &x, &y); UIText(font, x, y, text, color, scale, 0); ui_draw2d.SetFontScale(1.0f, 1.0f); }
int UIButton(int id, const LayoutManager &layout, float w, float h, const char *text, int button_align) { if (h == 0.0f) h = themeAtlas->images[theme.buttonImage].h; float x, y; layout.GetPos(&w, &h, &x, &y); if (button_align & ALIGN_HCENTER) x -= w / 2; if (button_align & ALIGN_VCENTER) y -= h / 2; if (button_align & ALIGN_RIGHT) x -= w; if (button_align & ALIGN_BOTTOM) y -= h; int txOffset = 0; int clicked = 0; for (int i = 0; i < MAX_POINTERS; i++) { // Check whether the button should be hot, use a generous margin for touch ease if (UIRegionHit(i, x, y, w, h, 8)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) { uistate.activeitem[i] = id; } } if (uistate.hotitem[i] == id) { if (uistate.activeitem[i] == id) { // Button is both 'hot' and 'active' txOffset = 2; } else { // Button is merely 'hot' } } else { // button is not hot, but it may be active } // If button is hot and active, but mouse button is not // down, the user must have clicked the button. if (uistate.mousedown[i] == 0 && uistate.hotitem[i] == id && uistate.activeitem[i] == id) { clicked = 1; } } // Render button if (h == themeAtlas->images[theme.buttonImage].h) ui_draw2d.DrawImage2GridH((txOffset && theme.buttonSelected) ? theme.buttonSelected : theme.buttonImage, x, y, x + w); else ui_draw2d.DrawImage4Grid((txOffset && theme.buttonSelected) ? theme.buttonSelected : theme.buttonImage, x, y, x + w, y + h); ui_draw2d.DrawTextShadow(theme.uiFont, text, x + w/2, y + h/2 + txOffset, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); uistate.lastwidget = id; return clicked; }
//------------------------------------------------------ void DrawSheet::addDrawOperation(DrawOperation* drawOp) { DrawBuffer* buf = getBufferForOperation(drawOp, true); assert(buf); if (buf) { buf->addDrawOperation(drawOp); mDrawOpMap[drawOp->getID()] = drawOp; drawOp->onSheetRegister(this); } }
int UICheckBox(int id, int x, int y, const char *text, int align, bool *value) { #ifdef _WIN32 const int h = 32; #else const int h = 48; #endif float tw, th; ui_draw2d.MeasureText(theme.uiFont, text, &tw, &th); int w = themeAtlas->images[theme.checkOn].w + UI_SPACE + tw; if (align & ALIGN_HCENTER) x -= w / 2; if (align & ALIGN_VCENTER) y -= h / 2; if (align & ALIGN_RIGHT) x -= w; if (align & ALIGN_BOTTOMRIGHT) y -= h; int txOffset = 0; int clicked = 0; for (int i = 0; i < MAX_POINTERS; i++) { // Check whether the button should be hot if (UIRegionHit(i, x, y, w, h, 8)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) uistate.activeitem[i] = id; } // Render button if (uistate.hotitem[i] == id) { if (uistate.activeitem[i] == id) { // Button is both 'hot' and 'active' txOffset = 2; } else { // Button is merely 'hot' } } else { // button is not hot, but it may be active } // If button is hot and active, but mouse button is not // down, the user must have clicked the button. if (uistate.mousedown[i] == 0 && uistate.hotitem[i] == id && uistate.activeitem[i] == id) { *value = !(*value); clicked = 1; } } ui_draw2d.DrawImage((*value) ? theme.checkOn : theme.checkOff, x, y+h/2, 1.0f, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); ui_draw2d.DrawTextShadow(theme.uiFont, text, x + themeAtlas->images[theme.checkOn].w + UI_SPACE, y + txOffset + h/2, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); uistate.lastwidget = id; return clicked; }
//------------------------------------------------------ void DrawSheet::_markDirty(DrawOperation* drawOp) { // Marking dirty could mean the buffer changes. // We ignore that. Atlasing can only happen before creating the Draw Ops. // look up the DrawBuffer for this DrawOp. DrawBuffer* buf = getBufferForOperation(drawOp); assert(buf); // mark the buffer dirty, queue the change buf->queueUpdate(drawOp); }
void TouchButton::draw(DrawBuffer &db, uint32_t color, uint32_t colorOverlay) { float scale = 1.0f; if (isDown_) { color |= 0xFF000000; colorOverlay |= 0xFF000000; scale = 2.0f; } scale *= scale_; // We only mirror background db.DrawImageRotated(imageIndex_, x_ + w_*scale_/2, y_ + h_*scale_/2, scale, rotationAngle_, color, mirror_h_); if (overlayImageIndex_ != -1) db.DrawImageRotated(overlayImageIndex_, x_ + w_*scale_/2, y_ + h_*scale_/2, scale, rotationAngle_, colorOverlay); }
//------------------------------------------------------ void DrawSheet::_sourceChanged(DrawOperation* op, const DrawSourcePtr& oldsrc) { DrawSourceBase::ID oldID = oldsrc->getSourceID(); DrawSourceBase::ID newID = op->getDrawSourceBase()->getSourceID(); if (oldID != newID) { DrawBuffer* dbo = getBufferForSourceID(oldID); DrawBuffer* dbn = getBufferForSourceID(newID); // remove from the old buffer // add into the new one dbo->removeDrawOperation(op); dbn->addDrawOperation(op); } }
void TouchCrossPad::draw(DrawBuffer &db, uint32_t color, uint32_t colorOverlay) { static const float xoff[4] = {1, 0, -1, 0}; static const float yoff[4] = {0, 1, 0, -1}; static const int dir[4] = {PAD_BUTTON_RIGHT, PAD_BUTTON_DOWN, PAD_BUTTON_LEFT, PAD_BUTTON_UP}; for (int i = 0; i < 4; i++) { float x = x_ + xoff[i] * scale_ * radius_; float y = y_ + yoff[i] * scale_ * radius_; float angle = i * M_PI / 2; float imgScale = (down_ & dir[i]) ? scale_ * 2 : scale_; db.DrawImageRotated(arrowIndex_, x, y, imgScale, angle + PI, color, false); if (overlayIndex_ != -1) db.DrawImageRotated(overlayIndex_, x, y, imgScale, angle + PI, colorOverlay); } }
int UIImageButton(int id, const LayoutManager &layout, float w, int image, int button_align) { float h = 64; float x, y; layout.GetPos(&w, &h, &x, &y); if (button_align & ALIGN_HCENTER) x -= w / 2; if (button_align & ALIGN_VCENTER) y -= h / 2; if (button_align & ALIGN_RIGHT) x -= w; if (button_align & ALIGN_BOTTOMRIGHT) y -= h; int txOffset = 0; int clicked = 0; for (int i = 0; i < MAX_POINTERS; i++) { // Check whether the button should be hot, use a generous margin for touch ease if (UIRegionHit(i, x, y, w, h, 8)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) uistate.activeitem[i] = id; } if (uistate.hotitem[i] == id) { if (uistate.activeitem[i] == id) { // Button is both 'hot' and 'active' txOffset = 2; } else { // Button is merely 'hot' } } else { // button is not hot, but it may be active§ } // If button is hot and active, but mouse button is not // down, the user must have clicked the button. if (uistate.mousedown[i] == 0 && uistate.hotitem[i] == id && uistate.activeitem[i] == id) { clicked = 1; } } // Render button ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); ui_draw2d.DrawImage(image, x + w/2, y + h/2 + txOffset, 1.0f, 0xFFFFFFFF, ALIGN_HCENTER | ALIGN_VCENTER); uistate.lastwidget = id; return clicked; }
void GameRenderer::drawColour(const glm::vec4& colour, glm::vec4 extents) { glUseProgram(ssRectProgram); // Move into NDC extents.x /= renderer->getViewport().x; extents.y /= renderer->getViewport().y; extents.z /= renderer->getViewport().x; extents.w /= renderer->getViewport().y; extents.x += extents.z / 2.f; extents.y += extents.w / 2.f; extents.x -= .5f; extents.y -= .5f; extents *= glm::vec4(2.f,-2.f, 1.f, 1.f); glEnable(GL_BLEND); glUniform2f(ssRectOffset, extents.x, extents.y); glUniform2f(ssRectSize, extents.z, extents.w); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glUniform1i(ssRectTexture, 0); glUniform4f(ssRectColour, colour.r, colour.g, colour.b, colour.a); glBindVertexArray( ssRectDraw.getVAOName() ); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Ooops renderer->invalidate(); }
void UIEnd() { for (int i = 0; i < MAX_POINTERS; i++) { if (uistate.mousedown[i] == 0) { uistate.activeitem[i] = 0; } else { if (uistate.activeitem[i] == 0) { uistate.activeitem[i] = -1; } } } ui_draw2d.End(); ui_draw2d_front.End(); if (uistate.ui_tick > 0) uistate.ui_tick--; }
void GameRenderer::renderLetterbox() { glUseProgram(ssRectProgram); const float cinematicExperienceSize = 0.15f; glUniform2f(ssRectOffset, 0.f, -1.f * (1.f - cinematicExperienceSize)); glUniform2f(ssRectSize, 1.f, cinematicExperienceSize); glBindTexture(GL_TEXTURE_2D, 0); glUniform1i(ssRectTexture, 0); glUniform4f(ssRectColour, 0.f, 0.f, 0.f, 1.f); glBindVertexArray( ssRectDraw.getVAOName() ); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glUniform2f(ssRectOffset, 0.f, 1.f * (1.f - cinematicExperienceSize)); glUniform2f(ssRectSize, 1.f, cinematicExperienceSize); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); }
void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; if (!strlen(str)) return; uint32_t stringHash = hash::Adler32((const uint8_t *)str, strlen(str)); uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24); target.Flush(true); TextStringEntry *entry; auto iter = cache_.find(entryHash); if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; } else { // Render the string to our bitmap and save to a GL texture. std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); SIZE size; auto iter = fontMap_.find(fontHash_); if (iter != fontMap_.end()) { SelectObject(ctx_->hDC, iter->second->hFont); } // Set text properties SetTextColor(ctx_->hDC, 0xFFFFFF); SetBkColor(ctx_->hDC, 0); SetTextAlign(ctx_->hDC, TA_TOP); // This matters for multi-line text - DT_CENTER is horizontal only. UINT dtAlign = (align & ALIGN_HCENTER) == 0 ? DT_LEFT : DT_CENTER; RECT textRect = { 0 }; DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_HIDEPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); size.cx = textRect.right; size.cy = textRect.bottom; // GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size); RECT rc = { 0 }; rc.right = size.cx + 4; rc.bottom = size.cy + 4; FillRect(ctx_->hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); //ExtTextOut(ctx_->hDC, 0, 0, ETO_OPAQUE | ETO_CLIPPED, NULL, wstr.c_str(), (int)wstr.size(), NULL); DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX | DT_TOP | dtAlign, 0); if (size.cx > MAX_TEXT_WIDTH) size.cx = MAX_TEXT_WIDTH; if (size.cy > MAX_TEXT_HEIGHT) size.cy = MAX_TEXT_HEIGHT; entry = new TextStringEntry(); entry->width = size.cx; entry->height = size.cy; entry->bmWidth = (size.cx + 3) & ~3; entry->bmHeight = (size.cy + 3) & ~3; entry->lastUsedFrame = frameCount_; DataFormat texFormat; // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; else texFormat = Draw::DataFormat::R8G8B8A8_UNORM; // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format // because we need white. Well, we could using swizzle, but not all our backends support that. TextureDesc desc{}; uint32_t *bitmapData32 = nullptr; uint16_t *bitmapData16 = nullptr; if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { bitmapData32 = new uint32_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { uint8_t bAlpha = (uint8_t)(ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff); bitmapData32[entry->bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; } } desc.initData.push_back((uint8_t *)bitmapData32); } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16) { bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); bitmapData16[entry->bmWidth * y + x] = (bAlpha) | 0xfff0; } } desc.initData.push_back((uint8_t *)bitmapData16); } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) {
void UIBegin() { for (int i = 0; i < MAX_POINTERS; i++) uistate.hotitem[i] = 0; ui_draw2d.Begin(); ui_draw2d_front.Begin(); }
GameRenderer::GameRenderer(Logger* log, GameData* _data) : data(_data) , logger(log) , renderer(new OpenGLRenderer) , _renderAlpha(0.f) , _renderWorld(nullptr) , cullOverride(false) , map(renderer, _data) , water(this) , text(this) { logger->info("Renderer", renderer->getIDString()); worldProg = renderer->createShader( GameShaders::WorldObject::VertexShader, GameShaders::WorldObject::FragmentShader); renderer->setUniformTexture(worldProg, "texture", 0); renderer->setProgramBlockBinding(worldProg, "SceneData", 1); renderer->setProgramBlockBinding(worldProg, "ObjectData", 2); particleProg = renderer->createShader( GameShaders::WorldObject::VertexShader, GameShaders::Particle::FragmentShader); renderer->setUniformTexture(particleProg, "texture", 0); renderer->setProgramBlockBinding(particleProg, "SceneData", 1); renderer->setProgramBlockBinding(particleProg, "ObjectData", 2); skyProg = renderer->createShader( GameShaders::Sky::VertexShader, GameShaders::Sky::FragmentShader); renderer->setProgramBlockBinding(skyProg, "SceneData", 1); postProg = renderer->createShader( GameShaders::DefaultPostProcess::VertexShader, GameShaders::DefaultPostProcess::FragmentShader); glGenVertexArrays( 1, &vao ); glGenTextures(1, &m_missingTexture); glBindTexture(GL_TEXTURE_2D, m_missingTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, kMissingTextureBytes); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glGenFramebuffers(1, &framebufferName); glBindFramebuffer(GL_FRAMEBUFFER, framebufferName); glGenTextures(2, fbTextures); glBindTexture(GL_TEXTURE_2D, fbTextures[0]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, fbTextures[1]); glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, 128, 128, 0, GL_RED, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbTextures[0], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbTextures[1], 0); // Give water renderer the data texture water.setDataTexture(1, fbTextures[1]); glGenRenderbuffers(1, fbRenderBuffers); glBindRenderbuffer(GL_RENDERBUFFER, fbRenderBuffers[0]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 128, 128); glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fbRenderBuffers[0] ); // Create the skydome size_t segments = skydomeSegments, rows = skydomeRows; float R = 1.f/(float)(rows-1); float S = 1.f/(float)(segments-1); std::vector<VertexP3> skydomeVerts; skydomeVerts.resize(rows * segments); for( size_t r = 0, i = 0; r < rows; ++r) { for( size_t s = 0; s < segments; ++s) { skydomeVerts[i++].position = glm::vec3( cos(2.f * M_PI * s * S) * cos(M_PI_2 * r * R), sin(2.f * M_PI * s * S) * cos(M_PI_2 * r * R), sin(M_PI_2 * r * R) ); } } skyGbuff.uploadVertices(skydomeVerts); skyDbuff.addGeometry(&skyGbuff); skyDbuff.setFaceType(GL_TRIANGLES); glGenBuffers(1, &skydomeIBO); std::vector<GLuint> skydomeIndBuff; skydomeIndBuff.resize(rows*segments*6); for( size_t r = 0, i = 0; r < (rows-1); ++r ) { for( size_t s = 0; s < (segments-1); ++s ) { skydomeIndBuff[i++] = r * segments + s; skydomeIndBuff[i++] = r * segments + (s+1); skydomeIndBuff[i++] = (r+1) * segments + (s+1); skydomeIndBuff[i++] = r * segments + s; skydomeIndBuff[i++] = (r+1) * segments + (s+1); skydomeIndBuff[i++] = (r+1) * segments + s; } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skydomeIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * skydomeIndBuff.size(), skydomeIndBuff.data(), GL_STATIC_DRAW); glBindVertexArray(0); glGenBuffers(1, &debugVBO); glGenTextures(1, &debugTex); glGenVertexArrays(1, &debugVAO); particleGeom.uploadVertices<ParticleVert>( { { 0.5f, 0.5f, 1.f, 1.f, 1.f, 1.f, 1.f}, {-0.5f, 0.5f, 0.f, 1.f, 1.f, 1.f, 1.f}, { 0.5f,-0.5f, 1.f, 0.f, 1.f, 1.f, 1.f}, {-0.5f,-0.5f, 0.f, 0.f, 1.f, 1.f, 1.f} }); particleDraw.addGeometry(&particleGeom); particleDraw.setFaceType(GL_TRIANGLE_STRIP); ssRectGeom.uploadVertices(sspaceRect); ssRectDraw.addGeometry(&ssRectGeom); ssRectDraw.setFaceType(GL_TRIANGLE_STRIP); ssRectProgram = compileProgram(GameShaders::ScreenSpaceRect::VertexShader, GameShaders::ScreenSpaceRect::FragmentShader); ssRectTexture = glGetUniformLocation(ssRectProgram, "texture"); ssRectColour = glGetUniformLocation(ssRectProgram, "colour"); ssRectSize = glGetUniformLocation(ssRectProgram, "size"); ssRectOffset = glGetUniformLocation(ssRectProgram, "offset"); const static int cylsegments = 16; std::vector<Model::GeometryVertex> cylverts; for(int s = 0; s < cylsegments; ++s) { float theta = (2.f*glm::pi<float>()/cylsegments) * (s+0); float gamma = (2.f*glm::pi<float>()/cylsegments) * (s+1); glm::vec2 p0( glm::sin(theta), glm::cos(theta) ); glm::vec2 p1( glm::sin(gamma), glm::cos(gamma) ); p0 *= 0.5f; p1 *= 0.5f; cylverts.push_back({glm::vec3(p0, 2.f), glm::vec3(), glm::vec2(0.45f,0.6f), glm::u8vec4(255, 255, 255, 50)}); cylverts.push_back({glm::vec3(p0,-1.f), glm::vec3(), glm::vec2(0.45f,0.4f), glm::u8vec4(255, 255, 255, 150)}); cylverts.push_back({glm::vec3(p1, 2.f), glm::vec3(), glm::vec2(0.55f,0.6f), glm::u8vec4(255, 255, 255, 50)}); cylverts.push_back({glm::vec3(p0,-1.f), glm::vec3(), glm::vec2(0.45f,0.4f), glm::u8vec4(255, 255, 255, 150)}); cylverts.push_back({glm::vec3(p1,-1.f), glm::vec3(), glm::vec2(0.55f,0.4f), glm::u8vec4(255, 255, 255, 150)}); cylverts.push_back({glm::vec3(p1, 2.f), glm::vec3(), glm::vec2(0.55f,0.6f), glm::u8vec4(255, 255, 255, 50)}); } cylinderGeometry.uploadVertices<Model::GeometryVertex>(cylverts); cylinderBuffer.addGeometry(&cylinderGeometry); cylinderBuffer.setFaceType(GL_TRIANGLES); }
void StringVectorListAdapter::drawItem(int item, int x, int y, int w, int h, bool selected) const { ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w); ui_draw2d.DrawTextShadow(theme.uiFont, (*items_)[item].c_str(), x + UI_SPACE , y, 0xFFFFFFFF, ALIGN_LEFT | ALIGN_VCENTER); }
void UIBegin(Thin3DShaderSet *shaderSet) { for (int i = 0; i < MAX_POINTERS; i++) uistate.hotitem[i] = 0; ui_draw2d.Begin(shaderSet); ui_draw2d_front.Begin(shaderSet); }
void UIBegin(const GLSLProgram *shader) { for (int i = 0; i < MAX_POINTERS; i++) uistate.hotitem[i] = 0; ui_draw2d.Begin(shader); ui_draw2d_front.Begin(shader); }
int UITextureButton(UIContext *ctx, int id, const LayoutManager &layout, float w, float h, Texture *texture, int button_align, uint32_t color, int drop_shadow) // uses current UI atlas for fetching images. { float x, y; layout.GetPos(&w, &h, &x, &y); if (button_align & ALIGN_HCENTER) x -= w / 2; if (button_align & ALIGN_VCENTER) y -= h / 2; if (button_align & ALIGN_RIGHT) x -= w; if (button_align & ALIGN_BOTTOMRIGHT) y -= h; int txOffset = 0; int clicked = 0; for (int i = 0; i < MAX_POINTERS; i++) { // Check whether the button should be hot, use a generous margin for touch ease if (UIRegionHit(i, x, y, w, h, 8)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) uistate.activeitem[i] = id; } if (uistate.hotitem[i] == id) { if (uistate.activeitem[i] == id) { // Button is both 'hot' and 'active' txOffset = 2; } else { // Button is merely 'hot' } } else { // button is not hot, but it may be active } // If button is hot and active, but mouse button is not // down, the user must have clicked the button. if (uistate.mousedown[i] == 0 && uistate.hotitem[i] == id && uistate.activeitem[i] == id) { clicked = 1; } } if (texture) { float tw = texture->Width(); float th = texture->Height(); // Adjust position so we don't stretch the image vertically or horizontally. // TODO: Add a param to specify fit? The below assumes it's never too wide. float nw = h * tw / th; x += (w - nw) / 2.0f; w = nw; } // Render button int dropsize = 10; if (drop_shadow && texture) { if (txOffset) { dropsize = 3; y += txOffset * 2; } ui_draw2d.DrawImage4Grid(drop_shadow, x - dropsize, y, x+w + dropsize, y+h+dropsize*1.5, blackAlpha(0.5f), 1.0f); ui_draw2d.Flush(true); } if (texture) { texture->Bind(0); } else { ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w, color); ui_draw2d.Flush(); Texture::Unbind(); } ui_draw2d.DrawTexRect(x, y, x+w, y+h, 0, 0, 1, 1, color); ui_draw2d.Flush(); ctx->RebindTexture(); uistate.lastwidget = id; return clicked; }
void TouchStick::draw(DrawBuffer &db, uint32_t color) { if (bgImageIndex_ != -1) db.DrawImage(bgImageIndex_, stick_x_, stick_y_, 1.0f * scale_, color, ALIGN_CENTER); db.DrawImage(stickImageIndex_, stick_x_ + stick_delta_x_ * stick_size_ * scale_, stick_y_ + stick_delta_y_ * stick_size_ * scale_, 1.0f * scale_, color, ALIGN_CENTER); }
void UIBegin(Thin3DShaderSet *shaderSet) { ui_draw2d.Begin(shaderSet); ui_draw2d_front.Begin(shaderSet); }
void UIText(int font, int x, int y, const char *text, uint32_t color, float scale, int align) { ui_draw2d.SetFontScale(scale, scale); ui_draw2d.DrawTextShadow(font, text, x, y, color, align); ui_draw2d.SetFontScale(1.0f, 1.0f); }
void UIFlush() { ui_draw2d.Flush(); ui_draw2d_front.Flush(); }
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 ); }