Determine if a sprite has been clicked on

Advanced OpenGL source port fork from ZDoom, picking up where ZDoomGL left off.
[Home] [Download] [Git builds (Win)] [Git builds (Mac)] [Wiki] [Repo] [Bugs&Suggestions]

Moderator: Graf Zahl

Xiphias3
Posts: 1
Joined: Tue May 17, 2016 4:25

Determine if a sprite has been clicked on

Post by Xiphias3 »

Hello. I want to be able to determine if I have clicked on a particular sprite. Overlapping are irrelevant. Graphics work so far has been very straight forward thanks to gl_RenderState hiding the open gl details. The idea is similar to gluProject, but I cant seem to get it to work, especially considering the vertex program running. So far this is what I'm thinking:

1. Get object coordinates via actor->X(), actor->Y(), actor->Z() and convert the float via FIXED2FLOAT
2. Transform object coordinates to final coordinates using main.vp
3. Call gluProject

Any help is appreciated

EDIT:

Ok, I made some progress. There is still an error though. Firing the weapon messes up the end result.
(Deleted old code)

EDIT2:

Ok, I solved it.
(Deleted old code)

Code: Select all

VSMatrix modelViewMatrix = gl_RenderState.mViewMatrix;
VSMatrix projectionMatrix = gl_RenderState.mProjectionMatrix;

GLdouble modelview[16], projection[16];
for (int j = 0; j < 16; j++) {
	modelview[j] = modelViewMatrix.get()[j];
	projection[j] = projectionMatrix.get()[j];
}

GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
	
float winX[4], winY[4], winZ[4];
float viewportX1 = viewport[0];
float viewportY1 = viewport[1];
float viewportX2 = viewportX1 + viewport[2];
float viewportY2 = viewportY1 + viewport[3];

GLDrawList& dl = gl_drawinfo->drawlists[GLDL_TRANSLUCENT];
for (unsigned int i = 0; i < dl.Size(); i++) {
	GLDrawItem& di = dl.drawitems[i];
	if (di.rendertype != GLDrawItemType::GLDIT_SPRITE) continue;

	GLSprite& sprite = dl.sprites[di.index];
	if (!sprite.actor || sprite.actor->tid == 0) continue;
		
	// Last sprite drawn position GLSprite::Draw()
	Vector v1 = sprite.v1; 
	Vector v2 = sprite.v2;
	Vector v3 = sprite.v3;
	Vector v4 = sprite.v4;

	float objX[4] = { v1.X(), v2.X(), v3.X(), v4.X() };
	float objY[4] = { v1.Y(), v2.Y(), v3.Y(), v4.Y() };
	float objZ[4] = { v1.Z(), v2.Z(), v3.Z(), v4.Z() };
		
	bool coordsOk = false;
		
	for (int j = 0, nPtsInViewport = 0; j < 4; j++) {
		GLdouble wx, wy, wz;
		GLint ret = gluProject(objX[j], objY[j], objZ[j], modelview, projection, viewport, &wx, &wy, &wz);
		if (ret != GL_TRUE || wz < 0.0 || wz > 1.0) break;
		if (wx >= viewportX1 && wx < viewportX2 && wy >= viewportY1 && wy < viewportY2) nPtsInViewport++;

		winX[j] = (float)wx;
		winY[j] = (float)(viewport[3] - wy);
		winZ[j] = (float)wz;
		coordsOk = j == 3 && nPtsInViewport > 0;
	}

	if (coordsOk) {
		// tl tr br bl
		// For a 4 sided simple polygon
		float x[4] = { winX[0], winX[1], winX[3], winX[2] };
		float y[4] = { winY[0], winY[1], winY[3], winY[2] };
		SpriteActorScreenPosition pos(x, y, sprite.actor);
		SpriteActorScreenPositions.Insert(sprite.actor->tid, pos);
	}
}

Return to “GZDoom”