Search the Community
Showing results for tags '2D'.
-
Hello community, long time no see. I am working on my own graphical user interface, for my super duper rpg game :). The use separate textures for each button state, etc. I consider it not effective! It is better to load the texture with the atlas of the whole GUI once. And use her. In order to draw a texture from the atlas, we need to slightly modify the standard shader (drawimage), and save it under a different name (drawimagerect). Shader #version 400 uniform vec4 drawcolor; uniform sampler2D texture0; uniform vec4 rect; in vec2 vTexCoords0; out vec4 fragData0; void main(void) { ivec2 ts = textureSize(texture0, 0); vec4 coord = vec4(rect.x / ts.x, rect.y / ts.y, rect.z / ts.x, rect.w / ts.y); vec2 uv = coord.xy + (vTexCoords0 * coord.zw); fragData0 = drawcolor * texture(texture0,uv); } Now we can draw a texture from the atlas: void drawImageRect(Texture* texture, float x, float y, Vec4 rect) { Context* context = Context::GetCurrent(); context->SetShader(Shader::Load("Shaders/Drawing/drawimagerect.shader")); context->GetShader()->SetVec4("rect", rect); context->DrawImage(texture, x, y, rect.z, rect.w); context->SetShader(NULL); } void drawImageRect(Texture* texture, float x, float y, float width, float height, Vec4 rect) { Context* context = Context::GetCurrent(); context->SetShader(Shader::Load("Shaders/Drawing/drawimagerect.shader")); context->GetShader()->SetVec4("rect", rect); context->DrawImage(texture, x, y, width, height); context->SetShader(NULL); } Animation To play the animation we need to get the coordinates of all the frames in the atlas. Naturally, we won't do this manually, will write a small algorithm. bool isEmptyFrame(char* pixels, int textureWidth, iVec2 position, iVec2 frameSize, const bool alpha=true, const iVec3 colorBg=iVec3()) { unsigned char r, g, b, a; int level = 0; for (int y = position.y; y < position.y + frameSize.y; y++) { for (int x = position.x; x < position.x + frameSize.x; x++) { int p = (y * textureWidth + x) * 4; memcpy(&r, pixels + p + 0, 1); memcpy(&g, pixels + p + 1, 1); memcpy(&b, pixels + p + 2, 1); memcpy(&a, pixels + p + 3, 1); if (!alpha) { if ((int)r == colorBg.r && (int)g == colorBg.g && (int)b == colorBg.b) { level++; } else { return false; } } else { if ((int)a == 0) { level++; } else { return false; } } } } float percent = (float)((float)level / (float)(frameSize.x * frameSize.y)) * 100.0f; if (percent >= 100.0f) { return true; } return false; } void getFrames(Texture* texture, iVec2 framesize, std::vector<Vec4> &frames) { if (texture == nullptr) return; int horizontLine = texture->GetWidth() / framesize.x; int verticalLine = texture->GetHeight() / framesize.y; int frameCount = horizontLine * verticalLine; int currentHorizont = 0; int currentVertical = 0; iVec2 framePosition = iVec2(); iVec2 frameSize = framesize; char* pixels = (char*)malloc(texture->GetMipmapSize(0) * 8); texture->GetPixels(pixels); System::Print((std::string)"Get frames from texture atlas \"" + texture->GetPath() + "\"..."); // Push first frame int skipCount = 0; if (!isEmptyFrame(pixels, texture->GetWidth(), framePosition, frameSize)) { frames.push_back(Vec4((float)framePosition.x, (float)framePosition.y, (float)frameSize.x, (float)frameSize.y)); } else { skipCount++; System::Print((std::string)"Frame #0" + " is empty. (skip)"); } for (int i = 1; i < frameCount; i++) { if (currentHorizont < horizontLine - 1) { currentHorizont++; framePosition.x = frameSize.x * currentHorizont; } else { if (currentVertical < verticalLine - 1) { currentVertical++; framePosition.x = 0; framePosition.y = frameSize.y * currentVertical; currentHorizont = 0; } } if (!isEmptyFrame(pixels, texture->GetWidth(), framePosition, frameSize)) { frames.push_back(Vec4((float)framePosition.x, (float)framePosition.y, (float)frameSize.x, (float)frameSize.y)); } else { skipCount++; System::Print((std::string)"Frame #" + std::to_string(i) + " is empty. (skip)"); } } System::Print((std::string)"Frame count: " + std::to_string(frames.size()) + ", skip: " + std::to_string(skipCount)); free(pixels); } Now that we have all the frames, we can play the animation. Texture* atlas = Texture::Load("Textures/atlas.tex"); std::vector<Vec4> frames; getFrames(atlas, iVec2(96, 96), frames); float frame = 0.0f; float frameend = frames.size(); float framebegin = 0.0f; float speed = 0.1f; //Loop frame += Time::GetSpeed() * speed; frame = fmodf(frame, frameend - framebegin) + framebegin; //Draw drawImageRect(atlas, 25.0f, 25.0f, frames[(int)frame]); Updates: [04.04.2020] [+] Added check for empty frames.
-
As I make an infrastructure for a new LE project - a simple logic puzzler with cuboid manipulation and matching - I have to use context rendering for GUI. As is well known, LE offers only a basic drawing functionalities, some of which are broken btw. To paliate the problem, I've written a simple 2D drawing library. The library offers such intuitive entities as text, rect, image and animation with accompanying methods such as SetPosition, SetRotation, SetScale, SetPivot (for rotation purposes), etc, as well as methods for testing mouse interaction and entities intersection. I've tried to make a lib API consistent with LE's interface. In this updated, I've optimized Interaction and Intersection candidate qualification check, made an API more consistent, and rewritten few functions here and there Here is a github repo. To use a lib, just put an LED folder in LE Scripts folder and use the Main.lua file from the LED repo.
-
While coding my lua GUI I found that I needed to be able to fill many 2d polygons. After looking at quite a few algorithms (I am very bad at math), I found one created in lua and felt that I needed to share. It was converted from the Corona lua which was in turn converted from PSP lua. I have modified it to work without change in Leadwerks See here for examples on how it works: http://forums.coronalabs.com/topic/8084-drawing-a-polygon-with-a-fill/ function rgbatovec4scalar(rgb,a) return Vec4(rgb[1]/256,rgb[2]/256,rgb[3]/256,a/256) end function paintPoly(poly, xoffset, yoffset, rgba) -- [url="http://forums.coronalabs.com/topic/8084-drawing-a-polygon-with-a-fill/"]http://forums.coronalabs.com/topic/8084-drawing-a-polygon-with-a-fill/[/url] local math_floor = math.floor local math_min = math.min local math_max = math.max local polyGroup = {} local n = table.getn(poly) local minY = poly[1].y local maxY = poly[1].y for i = 2, n do minY = math_min(minY, poly[i].y) maxY = math_max(maxY, poly[i].y) end for y = minY, maxY do local ints = {} local int = 0 local last = n for i = 1, n do local y1 = poly[last].y local y2 = poly[i].y if y1 < y2 then local x1 = poly[last].x local x2 = poly[i].x if (y >= y1) and (y < y2) then int = int + 1 ints[int] = math_floor((y - y1) * (x2 - x1) / (y2 - y1) + x1) end elseif y1 > y2 then local x1 = poly[last].x local x2 = poly[i].x if (y >= y2) and (y < y1) then int = int + 1 ints[int] = math_floor((y - y2) * (x1 - x2) / (y1 - y2) + x2) end end last = i end local i = 1 while i < int do polyfillcontex = Context:GetCurrent() polyfillcontex:SetColor(rgbatovec4scalar(rgba,rgba[4])) polyfillcontex:DrawLine(ints[i] + xoffset, y + yoffset, ints[i + 1] + xoffset, y + yoffset) i = i + 2 end end return polyGroup end
-
Hi guys, finally I have some more freetime back and have restarted developing with Leadwerks more intensively in C#. Currently I'm working on multiple extensions for the .NET Wrapper of Leadwerks and I'm also finishing / continuing developing my tools. Later I hope this will all fit in one easy to use framework. First here is a screen of new nightsky texture used in my lua daynight script (not completely correct scaled) : the texture was made by taking screenshots from the stellarium software ( http://www.stellarium.org ) and building a cubemap out of them. Also I have started an advanced 2D Library for Leadwerks.Net : This is the current 2D code for the image above: public void Render() { Drawing2D.Enabled = true; //Enables Rendering of 2D Elements in native OpenGL Drawing2D.SetViewRotation(m_angle2, 1024f/ 2f, 768f / 2f); //Rotates the complete Viewport around given point Drawing2D.SetBlend(BlendMode.Alpha); // Set differten Blendmodes Drawing2D.SetColor(255, 0, 0, 1.0f); // Set Color for the following drawing calls Drawing2D.DrawLine(0, 0, 1024, 768); // Draws a line Drawing2D.SetColor(0, 255, 0, 0.5f); Drawing2D.DrawLine(0, -100, 1024, 768); Drawing2D.SetColor(0, 0, 255, 0.5f); Drawing2D.DrawLine(0, 100, 1024, 768); Drawing2D.SetColor(255, 0, 255, .5f); // Set the Drawing Handle of the next items to draw //(eg: normally all items are rotated at their local [0,0] coordinate, this function offsets this point by the given point) //values of 10,10 would rotate the following rects around their center. Drawing2D.SetHandle(50, 50); for (int i = 0; i < 150; i++) { if (i % 2 == 0) Drawing2D.SetRotation(m_angle); //Sets current rotation for the following drawings else Drawing2D.SetRotation(-m_angle); Drawing2D.DrawRect(10.24f + i * 10.24f, 7.68f + i * 7.68f, 20, 20); // Draws a rect } m_angle += 0.02f; m_angle2 += 0.04f; Drawing2D.Enabled = false; // Disables raw OpenGL Mode } The module will have its own Image handling (Leadwerks textures can be used as well) and much more. This is a brief overview and will be continued...