So I am trying to create a simple methode for stretching images when rendering them. But because opengl works with these triangles instead of rectangles it sort of screws up.
as you can see the 2 parts of the triangle are stretched differently.
the code I have for this is the following:
public static void drawTexture(Texture texture, float x, float y, float x2, float y2, float x3, float y3, float x4, float y4){
if(cantRender()) return;
polyBatch.begin();
float[] vertices = new float[20];
float color = Color.WHITE.toFloatBits();
int idx = 0;
vertices[idx++] = x;
vertices[idx++] = y;
vertices[idx++] = color;
vertices[idx++] = 0;
vertices[idx++] = 1;
vertices[idx++] = x2;
vertices[idx++] = y2;
vertices[idx++] = color;
vertices[idx++] = 1;
vertices[idx++] = 1;
vertices[idx++] = x3;
vertices[idx++] = y3;
vertices[idx++] = color;
vertices[idx++] = 1;
vertices[idx++] = 0;
vertices[idx++] = x4;
vertices[idx++] = y4;
vertices[idx++] = color;
vertices[idx++] = 0;
vertices[idx++] = 0;
polyBatch.draw(texture, vertices, 0, 20);
polyBatch.end();
}
Renderer.drawTexture(testTexture, 100, 100, 500, 100, 400, 500, 200, 500);
I have found a fix on the internet, but I don't know how i can make it work in combination with libgdx. this is the article i found:
http://www.xyzw.us/~cass/qcoord/.
The problem is that it doesn't seem like libgdx supports all 4 of these variables like described in the article.
Related
I am working on z buffering with lines, and I am trying to find the depth of a certain pixel.
Here is my line drawing code:
void l(int x1, int y1, int z1, int x2, int y2, int z2, int cl)
{
int deltax = x2 - x1; // The difference in the x's
int deltay = y2 - y1; // The difference in the y's
int m = deltay / deltax; // The slope of the line (with deltax > 0)
for (int x = 0; x <= deltax; x++)
{
int y = m * x; // Calculate the y-value
int xcalc = x + x1;
int ycalc = round(y) + y1;
color[xcalc][ycalc].c = cl; // Draw the current pixel
}
}
and here is my struct and color variable:
struct distancecolor { //c = color, d = depth
int c;
float d;
};
distancecolor color[250][250];
d = depth of pixel and c = color of pixel, stored from 1-9, because it is a custom rendering engine.
All I want to do is take in x1, y1, and z1, and then use x2, y2, and z2 with an equation to find the distance from 0 to x, or the pixel being placed, on the line. Ask me for any other needed information.
I'm making my own graphics library and I have a Sprite class which is just an array of colors with a width and a height. I can set a pixel on the sprite by changing its color value. How can I draw a line on a sprite given a start position and an end position?
class Sprite
{
public:
Sprite();
public:
LongUtils::Pixel GetPixel(int32_t x, int32_t y) const;
bool SetPixel(int32_t x, int32_t y, Pixel p);
LongUtils::Pixel* GetData(); // return the *data
LongUtils::Pixel* GetBlockData(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
private:
LongUtils::Pixel* data = nullptr;
int32_t width = 0;
int32_t height = 0;
};
Use something like Bresenham's line algorithm. Here's an example:
void Line( float x1, float y1, float x2, float y2, const Color& color )
{
// Bresenham's line algorithm
const bool steep = (fabs(y2 - y1) > fabs(x2 - x1));
if(steep)
{
std::swap(x1, y1);
std::swap(x2, y2);
}
if(x1 > x2)
{
std::swap(x1, x2);
std::swap(y1, y2);
}
const float dx = x2 - x1;
const float dy = fabs(y2 - y1);
float error = dx / 2.0f;
const int ystep = (y1 < y2) ? 1 : -1;
int y = (int)y1;
const int maxX = (int)x2;
for(int x=(int)x1; x<=maxX; x++)
{
if(steep)
{
SetPixel(y,x, color);
}
else
{
SetPixel(x,y, color);
}
error -= dy;
if(error < 0)
{
y += ystep;
error += dx;
}
}
}
As the title suggests I'm having an issue with my windows console application in c++. So far I've created a class, Console, to represent all of the functions I repeatedly use to construct a windows console.
I implemented a line drawing algorithm and had up to 500 fps when filling the screen with magenta characters and drawing a line in white.
However, I implemented a triangle drawing algorithm next (just three line drawing calls consecutively) and was surprised to find out that the frame rate dropped to about 20. I removed this code again but the bad frame rate persisted. I really don't know why this has happend because I've essentially ended up not changing anything.
For reference, here is the Console code (without header):
Console::Console(int width, int height):
m_handle(GetStdHandle(STD_OUTPUT_HANDLE)),
m_width(width),
m_height(height),
m_screen({ 0, 0, 1, 1 }),
m_title(L"Demo"),
m_buffer(new CHAR_INFO[(size_t)m_width * (size_t)m_height])
{
memset(m_buffer, 0, sizeof(CHAR_INFO) * m_width * m_height);
}
Console::~Console()
{
if (m_buffer)
delete[] m_buffer;
}
int Console::Construct(int char_w, int char_h)
{
if (m_handle == INVALID_HANDLE_VALUE)
return BAD_HANDLE;
if (!SetConsoleWindowInfo(m_handle, true, &m_screen))
return WINDOW_INFO_ERROR;
COORD screen_coord = { (short)m_width, (short)m_height };
if (!SetConsoleScreenBufferSize(m_handle, screen_coord))
return SCREEN_BUFFER_SIZE_ERROR;
CONSOLE_FONT_INFOEX cinfo;
cinfo.cbSize = sizeof(cinfo);
cinfo.dwFontSize.X = (short)char_w;
cinfo.dwFontSize.Y = (short)char_h;
cinfo.FontFamily = FF_DONTCARE;
cinfo.FontWeight = FW_NORMAL;
cinfo.nFont = 0;
wcscpy_s(cinfo.FaceName, L"Consolas");
if (!SetCurrentConsoleFontEx(m_handle, false, &cinfo))
return CONSOLE_FONT_ERROR;
CONSOLE_SCREEN_BUFFER_INFO cbuffinfo;
if (!GetConsoleScreenBufferInfo(m_handle, &cbuffinfo))
return GET_BUFFER_INFO_ERROR;
if (cbuffinfo.dwMaximumWindowSize.X < m_width)
return HORIZONTAL_SIZE_TOO_LARGE_ERROR;
if (cbuffinfo.dwMaximumWindowSize.Y < m_height)
return VERTICAL_SIZE_TOO_LARGE_ERROR;
m_screen = { 0, 0, (short)m_width - 1, (short)m_height - 1 };
if (!SetConsoleWindowInfo(m_handle, true, &m_screen))
return WINDOW_INFO_ERROR;
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandleClose, true))
return CLOSE_HANDLER_ERROR;
return OK;
}
void Console::Start()
{
active = true;
std::thread t(&Console::DoLoop, this);
t.join();
}
void Console::DoLoop()
{
if (!OnCreate())
active = false;
std::chrono::high_resolution_clock::time_point t1, t2;
t1 = std::chrono::high_resolution_clock::now();
t2 = t1;
while (active)
{
t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> diff = t2 - t1;
t1 = t2;
float dt = diff.count();
if (!OnUpdate(dt))
active = false;
wchar_t title_buff[256];
swprintf_s(title_buff, L"Console Application - %s - FPS: %3.2f", m_title.c_str(), 1.0f / dt);
SetConsoleTitle(title_buff);
WriteConsoleOutput(m_handle, m_buffer, { (short)m_width, (short)m_height }, { 0, 0 }, &m_screen);
}
finished.notify_one();
}
void Console::Fill(int x, int y, short glyph, short color)
{
if (x < 0 || y < 0 || x >= m_width || y >= m_height) return;
CHAR_INFO& ci = m_buffer[y * m_width + x];
ci.Char.UnicodeChar = glyph;
ci.Attributes = color;
}
void Console::Fill(int x1, int y1, int x2, int y2, short glyph, short color)
{
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x1 >= m_width) return;
if (y1 >= m_height) return;
if (x2 >= m_width) x2 = m_width - 1;
if (y2 >= m_height) y2 = m_height - 1;
if (x2 < 0) return;
if (y2 < 0) return;
for (int x = x1; x <= x2; x++)
{
for (int y = y1; y <= y2; y++)
{
CHAR_INFO& ci = m_buffer[y * m_width + x];
ci.Char.UnicodeChar = glyph;
ci.Attributes = color;
}
}
}
void Console::Clear(short glyph, short color)
{
for (int x = 0; x < m_width; x++)
{
for (int y = 0; y < m_height; y++)
{
CHAR_INFO& ci = m_buffer[y * m_width + x];
ci.Char.UnicodeChar = glyph;
ci.Attributes = color;
}
}
}
void Console::Line(int x1, int y1, int x2, int y2, short glyph, short color)
{
int dx = x2 - x1;
int dy = y2 - y1;
int adx = dx > 0 ? dx : -dx;
int ady = dy > 0 ? dy : -dy;
int dy2 = dy + dy;
int dx2 = dx + dx;
int adx2 = dx2 > 0 ? dx2 : -dx2;
int ady2 = dy2 > 0 ? dy2 : -dy2;
if (adx > ady)
{
if (x1 > x2)
{
int x = x1;
x1 = x2;
x2 = x;
dx = -dx;
dx2 = -dx2;
int y = y1;
y1 = y2;
y2 = y;
dy = -dy;
dy2 = -dy2;
}
int sy = dy > 0 ? 1 : dy < 0 ? -1 : 0;
int err = ady;
for (int x = x1, y = y1; x <= x2; x++)
{
Fill(x, y, glyph, color);
err += ady2;
if (err > adx2)
{
err -= adx2;
y += sy;
}
}
}
else
{
if (y1 > y2)
{
int x = x1;
x1 = x2;
x2 = x;
dx = -dx;
dx2 = -dx2;
int y = y1;
y1 = y2;
y2 = y;
dy = -dy;
dy2 = -dy2;
}
int sx = dx > 0 ? 1 : dx < 0 ? -1 : 0;
int err = adx;
for (int x = x1, y = y1; y <= y2; y++)
{
Fill(x, y, glyph, color);
err += adx2;
if (err > ady2)
{
err -= ady2;
x += sx;
}
}
}
}
void Console::Triangle(int x1, int y1, int x2, int y2, int x3, int y3, short glyph, short color)
{
Line(x1, y1, x2, y2, glyph, color);
Line(x2, y2, x3, y3, glyph, color);
Line(x3, y3, x1, y1, glyph, color);
}
BOOL Console::HandleClose(DWORD evt)
{
if (evt == CTRL_CLOSE_EVENT)
{
active = false;
std::unique_lock<std::mutex> ul(lock);
finished.wait(ul);
}
return true;
}
Here is the very short main code:
class Game : public Console
{
public:
Game(int width, int height):
Console(width, height)
{
}
bool OnCreate() override
{
return true;
}
bool OnUpdate(float dt) override
{
Clear(GLYPH_SOLID, FG_BLACK);
//Triangle(20, 20, 300, 40, 150, 200);
return true;
}
};
int main()
{
Game game(400, 300);
int err = game.Construct(2, 2);
if (err == Console::OK)
game.Start();
}
The error constants are just defined integer codes in the header file.
If any additional code is needed please let me know. Thanks in advance!
EDIT:
In OpenGL, when I want to draw a filled circle, I'd do:
void DrawPoint(float X, float Y, float Z, float Radius) const
{
glRasterPos2f(X, Y);
glPointSize(Radius);
glBegin(GL_POINTS);
glVertex3f(X, Y, Z);
glEnd();
glPointSize(this->PointSize);
glFlush();
}
However, I could not find any equivalent for glPointSize in Direct-X. So I tried:
struct Vector3
{
double X, Y, Z;
};
#include <vector>
void DrawCircle1(float X, float Y, DWORD Color)
{
const int sides = 20;
std::vector<D3DXVECTOR3> points;
for(int i = 0; i < sides; ++i)
{
double angle = D3DX_PI * 2 / sides * i;
points.emplace_back(D3DXVECTOR3(sin(angle), cos(angle), 0));
}
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, sides, &points[0], sizeof(D3DXVECTOR3));
}
void DrawCircle2(float CenterX, float CenterY, float Radius, int Rotations)
{
std::vector<D3DXVECTOR3> Points;
float Theta = 2 * 3.1415926535897932384626433832795 / float(Rotations);
float Cos = cosf(Theta);
float Sine = sinf(Theta);
float X = Radius, Y = 0, Temp = 0;
for(int I = 0; I < Rotations; ++I)
{
Points.push_back(D3DXVECTOR3(X + CenterX, Y + CenterY, 0));
Temp = X;
X = Cos * X - Sine * Y;
Y = Sine * Temp + Cos * Y;
}
device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, Points.size(), &Points[0], sizeof(D3DXVECTOR3));
}
But none of these work. I cannot figure out why nothing works. The first one draws a gigantic circle that is black and the second one draws a long triangle.
Any ideas how I can draw a filled in circle or a point of a certain size and colour in Direct-X?
static const int CIRCLE_RESOLUTION = 64;
struct VERTEX_2D_DIF { // transformed colorized
float x, y, z, rhw;
D3DCOLOR color;
static const DWORD FVF = D3DFVF_XYZRHW|D3DFVF_DIFFUSE;
};
void DrawCircleFilled(float mx, float my, float r, D3DCOLOR color)
{
VERTEX_2D_DIF verts[CIRCLE_RESOLUTION+1];
for (int i = 0; i < CIRCLE_RESOLUTION+1; i++)
{
verts[i].x = mx + r*cos(D3DX_PI*(i/(CIRCLE_RESOLUTION/2.0f)));
verts[i].y = my + r*sin(D3DX_PI*(i/(CIRCLE_RESOLUTION/2.0f)));
verts[i].z = 0;
verts[i].rhw = 1;
verts[i].color = color;
}
m_pDevice->SetFVF(VERTEX_2D_DIF::FVF);
m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, CIRCLE_RESOLUTION-1, &verts, sizeof(VERTEX_2D_DIF));
}
As question says, I want to draw a line starting at X,Y position to, for example, 10 pixels on mouse direction... The function I already have draws a line between 2 points, but I can't figure how to do it with a constant lenght on mouse direction
Here is the function:
void D3DGraphics::DrawLine( int x1,int y1,int x2,int y2,int r,int g,int blu )
{
int dx = x2 - x1;
int dy = y2 - y1;
if( dy == 0 && dx == 0 )
{
PutPixel( x1,y1,r,g,blu );
}
else if( abs( dy ) > abs( dx ) )
{
if( dy < 0 )
{
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
float m = (float)dx / (float)dy;
float b = x1 - m*y1;
for( int y = y1; y <= y2; y = y + 1 )
{
int x = (int)(m*y + b + 0.5f);
PutPixel( x,y,r,g,blu );
}
}
else
{
if( dx < 0 )
{
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
float m = (float)dy / (float)dx;
float b = y1 - m*x1;
for( int x = x1; x <= x2; x = x + 1 )
{
int y = (int)(m*x + b + 0.5f);
PutPixel( x,y,r,g,blu );
}
}
}
I also have a function that gets the mouse X and Y position on the screen (getmouseX(), getmouseY())
Direct3D has D3DXVECTOR2, D3DXVECTOR3, D3DXCOLOR and similar structures. You should probably use them. Or use typedef D3DXVECTOR2 Vec2; or something like that. Those structures come with mathematical functions, so using them makes sense. Oh, and they operate on floats.
Drawing one pixel at a time is a bad theme - it is slow. Also you can easily draw entire line in one call using IDirect3DDevice9->DrawPrimitive(D3DPT_LINELIST..)
Even if you don't want to use D3DX* structures, you should probably use strctures to store colors and coordinates:
Example:
struct Coord{
int x, y;
};
struct Color{
unsigned char a, b, g, r;
};
regarding your question.
typedef D3DXVECTOR2 Vec2;
....
Vec2 startPos = ...;
Vec2 endPos = getMousePos();
const float desiredLength = ...;//whatever you need here.
Vec2 diff = endPos - startPos; //should work. If it doesn't, use
//D3DXVec2Subtract(&diff, &endPos, &startPoss);
float currentLength = D3DXVec2Length(&diff);
if (currentLength != 0)
D3DXVec2Scale(&diff, &diff, desiredLength/currentLength);// diff *= desiredLength/currentLength
else
diff = Vec2(0.0f, 0.0f);
endPos = startPos + diff; //if it doesn't work, use D3DXVec2Add(&endPos, &startPos, &diff);
This way endPos will not be further than desiredLength than startPos. Unless startPos == endPos
P.S. If you REALLY want to draw the line yourself, you may want to research bresenham line drawing algorithm.
ratio = (length betweeen start position and mouse position)/10
x = startX+(mouseX-startX)/ratio
y = startY+(mouseY-startY)/ratio
I think its something like this