Jump to content

martyj

Members
  • Posts

    544
  • Joined

  • Last visited

Posts posted by martyj

  1. 3 hours ago, Rick said:

    So you're using the veg system for positions/rotation only? If you are replacing every tree in the veg system with an instance of a model, that's what you said right? I would think you would lose performance of the veg system then if you did that right as that has billboards and such where your model instances wouldn't or are you doing your own LOD type thing and that's what the distance check is for?

    We do loose some performance no doubt as w use Entity objects rather than billboards. We also loose some range as well due to this as well. You're correct that we use the veg system for position and rotation. If someone wanted to, they could extend the radius around this using custom LOD models to provide more of a "billboard" affect.

     

    Quote

    I was thinking you were replacing the veg trees to instance models JUST around the player since if possible that would really be all you need to do, but the problem is being able to tab into the veg system to do something like that.


    We do "replace" vegetation items around the player only, but you can't mix the two. With Leadwerks you cannot hide a specific vegetation object. You either hide everything or nothing.


    Benefits:
    1. Allows animated models to be placed as easily as vegetation
    2. Allows us to hide/show specific vegetation trees as players interact with them

    Cons:
    1. Less distance with vegetation since we don't support billboards
    2. Performance hit of trading 1 vegetation layer vs 50 Entity objects.


    World Factions uses this technique for 2 use cases.

    1. Players can cut down any tree in the game. This allows us to place trees with the vegetation system, but provides user interactive content. The tree that the player cuts down is made of two Entities. A top half of tree, and a bottom trunk. When the player cuts the tree, we enable physics on the Tree and provide a random force on the top half to "cut it down"

    2. Animals in the game. These are animated models with a small amount of AI added to them. We use the vegetation information for starting point. Players can kill specific animals so we need to hide them.



     


  2.  

    Quote

    This looks cool but it seems it may not be that efficient? If I'm reading it correctly you're loading the tree model for every vegetation model that exists on startup. Then inside each of those models you're checking the distance to the player to determine if you should do something. Just thinking that's a lot of checks happening per game loop. Could you not go the opposite direction and do AABB check in a range around the player, then loop only through those to make them real models vs veg? Keep that list so the next iteration when you loop again you can tell which ones are no longer in the list and change those back to veg vs model? Seems like you'd loop through a lot less veg overall each iteration.

     

    Where are you able to manipulate the veg system to hide specific trees? I didn't think they were accessible that way?


    We're not loading the model for tree every vegetation model. We do a model->Instnace. Have a look at VegetatedModel class. It loads VEG_MODEL_ENTITY_COUNT number of models via model->Instance.

    For your second comment we do an AABB check around the player position like you have suggested. We find all entities in a "boxSize" around the player.

     

    AABB scope = AABB(playerPosit.x-boxSizeX, -1000, playerPosit.z-boxSizeZ, playerPosit.x+boxSizeX, 1000, playerPosit.z+boxSizeZ);



    For your last question, we hide everything on the Veg System and use real Instanced models instead.

     

     

    ====================

     

     

    Edit:

     

    I see what you're saying.

    This code can be removed.

     

    AABB aabb = world->aabb;
    			std::vector<Mat4> instances;
    			layer->GetInstancesInAABB(aabb, instances);
    			System::Print("Loading Layer: " + parentName + " of Size: " + std::to_string(instances.size()));
    			for (unsigned int j = 0; j < instances.size(); j++)
    			{
    				Mat4 instance = instances[j];
    
    				Entity* copy = model->Instance(true, false);
    				copy->SetMatrix(instance, true);
    
    				copy->SetScale(scale);
    			}

     

  3. I had to do this for my game, it's possible, just not with the vegetation system exactly.

    You have to convert vegetation instances into real Entity objects.

    Due to performance reasons, you can't convert every vegetation object to an entity, so you have to be smart, and look at the closest objects to the player.

    I used a pool of about 50 objects and moved them to the closest trees around a player.

    I would sticky a vegetation entity to a specific tree as well, so if you started cutting one tree down, and you moved a little bit, you could go back to that tree and finish it off.

    Here is the C++ code. (Headers not included)

     

    VegetationToEntity

    -- Converts a vegetation layer into multiple VegetatedModel classes

    bool findStringIC(const std::string & strHaystack, const std::string & strNeedle)
    	{
    		auto it = std::search(
    				strHaystack.begin(), strHaystack.end(),
    				strNeedle.begin(),   strNeedle.end(),
    				[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }
    		);
    		return (it != strHaystack.end() );
    	}
    
    	void VegetationToEntity::LoadVegetationLayer(World* world)
    	{
    		App* app = App::GetApp();
    		if (app == nullptr)
    		{
    			return;
    		}
    
    		if (world->terrain == nullptr)
    		{
    			return;
    		}
    
    		std::map<std::string, bool> limitEntityMap = {
    				{ "Antelope", true },
    				{ "Deer", true },
    				{ "Lamb", true },
    				{ "Sheep", true },
    				{ "Wolf", true },
    		};
    
    		std::map<std::string, std::string> vegNameEntMap = {
    				{ "oak", "OakTree" },
    				{ "maple", "MapleTree" },
    				{ "birch", "BirchTree" },
    				{ "green", "GreenheartTree" },
    				{ "giantwood", "RedwoodTree" },
    				{ "weep",  "WillowTree" },
    				{ "mud", "MudHole" },
    				{ "antelope", "Antelope" },
    				{ "fallowdeer", "Deer" },
    				{ "lamb", "Lamb" },
    				{ "sheep", "Sheep" },
    				{ "wolf", "Wolf" },
    		};
    
    		int vegCount = world->terrain->CountVegetationLayers();
    		for (int i = 0; i < vegCount; i++)
    		{
    			VegetationLayer* layer = world->terrain->GetVegetationLayer(i);
    			std::string modelPath = layer->modelpath;
    
    			std::string parentName = "";
    			System::Print(modelPath);
    			for (auto it = vegNameEntMap.begin(); it != vegNameEntMap.end(); it++)
    			{
    				System::Print(it->first);
    				if(findStringIC(modelPath, it->first))
    				{
    					parentName = it->second;
    					break;
    				}
    			}
    
    			if (parentName.empty())
    			{
    				continue;
    			}
    
    			Entity* model = world->FindEntity(parentName);
    			if (model == nullptr)
    			{
    				continue;
    			}
    
    			// Hide Layer
    			layer->viewrange = 0;
    
    			if (limitEntityMap[parentName])
    			{
    				models.push_back(new VegetatedModel(layer, model, parentName));
    				continue;
    			}
    
    			Vec3 scale = model->GetScale();
    
    			AABB aabb = world->aabb;
    			std::vector<Mat4> instances;
    			layer->GetInstancesInAABB(aabb, instances);
    			System::Print("Loading Layer: " + parentName + " of Size: " + std::to_string(instances.size()));
    			for (unsigned int j = 0; j < instances.size(); j++)
    			{
    				Mat4 instance = instances[j];
    
    				Entity* copy = model->Instance(true, false);
    				copy->SetMatrix(instance, true);
    
    				copy->SetScale(scale);
    			}
    		}
    	}
    	// Called manually in App::Loop
    	void VegetationToEntity::UpdateWorld()
    	{
    		for (auto it = models.begin(); it != models.end(); it++)
    		{
    			VegetatedModel* model = *it;
    			model->UpdateWorld();
    		}
    	}



    The next class is where the work comes in. VegetatedModel represents a single Vegetation Layer as N number of entities. This will auto-populate the entities around the players positions as the player moves.
     

    VegetatedModel::VegetatedModel(VegetationLayer* layer, Entity* model, std::string className)
    	{
    		this->layer = layer;
    		this->cameraPosit = Vec3(0);
    
    		for (int i = 0; i < VEG_MODEL_ENTITY_COUNT; i++)
    		{
    			Entity* copy = model->Instance(true, false);
    			WFModel* model = Binder::InitCtor(copy, className);
    
    			this->realEntities[i] = new VegetatedEntity(model, copy);
    		}
    	}
    
    	void VegetatedModel::UpdateWorld()
    	{
    		Player* p = Player::GetPlayer();
    		if (p == NULL)
    		{
    			return;
    		}
    
    		Vec3 playerPosit = p->GetPosition();
    		if (this->cameraPosit.DistanceToPoint(playerPosit) < 4)
    		{
    			return;
    		}
    
    		this->cameraPosit = playerPosit;
    
    		int boxSizeX = 30;
    		int boxSizeZ = 30;
    		AABB scope = AABB(playerPosit.x-boxSizeX, -1000, playerPosit.z-boxSizeZ, playerPosit.x+boxSizeX, 1000, playerPosit.z+boxSizeZ);
    
    		World* world = World::GetCurrent();
    		std::vector<Vec3> possiblePoints(0);
    		std::vector<Mat4> instances(0);
    		this->layer->GetInstancesInAABB(world->aabb, instances);
    		for (unsigned int j = 0; j < instances.size(); j++)
    		{
    			Mat4 mat = instances[j];
    			possiblePoints.push_back(mat.GetTranslation());
    		}
    
    		std::sort(possiblePoints.begin(), possiblePoints.end(), VegetatedModel::PointSort);
    
    		// First VEG_MODEL_ENTITY_COUNT as we want to show only the closest point
    		if (possiblePoints.size() > VEG_MODEL_ENTITY_COUNT)
    		{
    			possiblePoints.erase(possiblePoints.begin() + VEG_MODEL_ENTITY_COUNT, possiblePoints.end());
    		}
    		
    		std::vector<VegetatedEntity*> entitiesNeedingPoints;
    		std::vector<Vec3> pointsToRemove;
    		int Count = Math::Min(possiblePoints.size(), VEG_MODEL_ENTITY_COUNT);
    		for (int i = 0 ; i < Count; i++)
    		{
    			VegetatedEntity* vegEntity = this->realEntities[i];
    			Entity* ent = vegEntity->GetEntity();
    			
    			bool found = false;
    			for (int j = 0; j < Count; j++)
    			{
    				Vec3 posit = possiblePoints[j];
    				if (vegEntity->GetVegetationPosition() == posit)
    				{
    					found = true;
    					pointsToRemove.push_back(posit);
    					break;
    				}
    			}
    
    			if (!found)
    			{
    				entitiesNeedingPoints.push_back(vegEntity);
    			}
    		}
    
    		std::vector<Vec3> newPossiblePoints;
    		for (int i = 0; i < possiblePoints.size(); i++)
    		{
    			Vec3 possiblePoint = possiblePoints[i];
    			bool found = false;
    			for (auto it = pointsToRemove.begin(); it != pointsToRemove.end(); it++)
    			{
    				Vec3 pointRemove = *it;
    				if (possiblePoint == pointRemove)
    				{
    					found = true;
    					break;
    				}
    			}
    
    			if (!found)
    			{
    				newPossiblePoints.push_back(possiblePoint);
    			}
    		}
    		possiblePoints = newPossiblePoints;
    
    		int numEntitiesToSet = Math::Min(possiblePoints.size(), entitiesNeedingPoints.size());
    		for (int i = 0; i < numEntitiesToSet; i++)
    		{
    			VegetatedEntity* vegEntity = entitiesNeedingPoints[i];
    			Entity* ent = vegEntity->GetEntity();
    			WFModel* model = vegEntity->GetWFModel();
    
    			Vec3 point = possiblePoints[i];
    			vegEntity->SetVegetationPosition(point);
    			model->Reset();
    		}
    
    		// Remove unused entities
    		for (unsigned int i = numEntitiesToSet; i < entitiesNeedingPoints.size(); i++)
    		{
    			VegetatedEntity* vegEntity = entitiesNeedingPoints[i];
    			Entity* ent = vegEntity->GetEntity();
    			//vegEntity->SetVegetationPosition(Vec3(0, -123, 0));
    			//ent->Hide();
    		}
    	}
    
    	bool VegetatedModel::PointSort(Vec3 posit1, Vec3 posit2)
    	{
    		Player* p = Player::GetPlayer();
    		if (p == NULL)
    		{
    			return 0;
    		}
    
    		double d1 = p->GetPosition().DistanceToPoint(posit1);
    		double d2 = p->GetPosition().DistanceToPoint(posit2);
    
    		return d1 < d2;
    	}



     

    • Like 4
  4. An game engine is exploitable. It's why valve has VAC software.

    IMO player movement is a fairly small exploit. Depending on the type of game you are making, there are exploits far more damaging.

    FPS - suffers from auto-aim bots
    MMORPG - Duplicate items, auto xp

    Player movement hacks are less likely as you have to find the memory address of the player positions in the application memory and then modify that memory externally.

    Auto-aim bots, and auto xp bots are more likely as you don't have to worry about cross application memory. On most modern operating systems application memory is stored in pages. These pages are protected by the operating system to make sure your program doesn't bump into another applications memory. A common way to get past this protection is to do DLL injection. Basically take a commonly used DLL by your game (libcurl for example), modify the library to function exactly how it normally does, plus add in hooks to let you control the game.

    TLDR:

    Yes

  5. Texture::SetPixels doesn't work in windows:

    Linux Screenshot:

    linux.thumb.png.e33fafee9e15199fb3562f13357a02f5.png

     

    Windows Screenshot:

     

    windows.thumb.png.1872bfcead531ee8cf96d9ab37ab8245.png

    imageproxy.php?img=&key=93667c899a2c8479imageproxy.php?img=&key=93667c899a2c8479Code:
     

    virtual void RenderBuffer(unsigned char* buffData, int width, int height)
        {
            this->texture->SetPixels((const char*)buffData, 0, 0, 0);
        }



    I can get Windows to work by manually setting each pixel, but it's hella slow performance.


    Here is a TGA of what I am trying to render in Linux. (Raw BGRA image format with first 36 bytes being a header)

     

    linux_render_21_36.tga


    TGA for Windows:

    render_windows2.tga


     

  6. So the one major issue I have at the moment is as follows:
     

     mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'


    For some reason it is passing /MDd to the compiler instead of /MT

    I will have a look at your CMake project tomorrow to see if I can resolve it based off that.

  7. @reepblue

    That's the goal. To use a single CMake script for Linux and Windows.

    Right now I have to maintain a VS project for Windows, and a CMake for Linux.

    There are a lot of caveats to getting CMake for windows to work, such as setting /SUBSYTEM:CONSOLE having the correct MD/MT/MTd flags. Things that normally just work out of the box for visual studio. 

     

  8. @Josh

    How would Upwork work as my task requires the professional C++ license for Leadwerks?

    My concern for switching to Steamworks library is I already have CEF working well in my game. I'm just trying to not have to maintain a Visual Studio Project for Windows and CMake project for Linux. If I can get CMake to work on Windows I am set. 

  9. I'm looking for a C++ freelancer to "port" a library and example project into Windows.

    The library is a wrapper around Chromium Embedded Framework.

    The example project is just using the library in a Leadwerks sample.

    There probably isn't any C++ coding required, but more of CMake configurations. (CMake is a requirement. No Visual Studio projects.)

    PM me if you're interested, include your hourly rate, and a resume/work history.

     

  10. From a Leadwerks Pro perspective.

    Linux is a hell of a lot easier to deal with.

    From a Leadwerks perspective, the Leadwerks UI on Linux is no where near the quality of that in Windows. It's this fact alone that's probably hurting Leadwerks Linux. If I need to make a map change. I dual boot into windows to make changes to the map.

    I have been on Leadwerks Linux for the last year

    I currently use kubuntu 18.04.

  11. So I have it rendering to a file/texture in a background thread.

    What I'd like to do now is to use wglShareLists to have textures synced between the Leadwerks Context and the SDL_Context to render a GL_TEXTURE_2D.

    What's the best way to create a Leadwerks::Texture from a GLuint? If I don't have to call glReadPixels to render a texture, it will probably help with performance.

     

    I assume if I set these values it will work to call context->DrawImage?

            int filtermode -> Pixel;
            int format -> RGBA8;
            int target -> Texture2D;
            bool hasmipmaps -> false;
            static float anisotropy -> What goes here?
            int bindindex -> output from glGenTextures;
            int width -> FBO Width;
            int height -> FBO height;
            int depth -> 0;
            bool clamp[3] -> What goes here?
            int currentmiplevel -> What goes here?
            int samples -> 0;

  12. This post is for future reference. I don't have it working with a 2nd off screen context. I have two threads rendering two scenes to two windows.

    I think my next steps is to ditch SDL and use Frame Buffer Objects.
    https://www.khronos.org/opengl/wiki/Framebuffer_Object

    I'll update people on my progress.

     

    
    #include <Leadwerks.h>
    
    #include <SDL.h>
    
    using namespace Leadwerks;
    
    
    #include <GL/glut.h>
    
    GLfloat light_diffuse[] = { 1.0, 0.0, 0.0, 1.0 };  /* Red diffuse light. */
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };  /* Infinite light location. */
    GLfloat n[6][3] = {  /* Normals for the 6 faces of a cube. */
      {-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0},
      {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} };
    GLint faces[6][4] = {  /* Vertex indices for the 6 faces of a cube. */
      {0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4},
      {4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} };
    GLfloat v[8][3];  /* Will be filled in with X,Y,Z vertexes. */
    
    void drawBox(void)
    {
    	int i;
    
    	for (i = 0; i < 6; i++) {
    		glBegin(GL_QUADS);
    		glNormal3fv(&n[i][0]);
    		glVertex3fv(&v[faces[i][0]][0]);
    		glVertex3fv(&v[faces[i][1]][0]);
    		glVertex3fv(&v[faces[i][2]][0]);
    		glVertex3fv(&v[faces[i][3]][0]);
    		glEnd();
    	}
    }
    
    void screendump(int W, int H)
    {
    	FILE* out = fopen("screenshot.tga", "wb");
    	char* pixel_data = new char[3 * W*H];
    	short TGAhead[] = { 0, 2, 0, 0, 0, 0, W, H, 24 };
    
    	glReadBuffer(GL_RENDERBUFFER_EXT);
    	glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data);
    	// TODO: Render to texture instead. Use texture with Context::drawImage
    	fwrite(&TGAhead, sizeof(TGAhead), 1, out);
    	fwrite(pixel_data, 3 * W*H, 1, out);
    	fclose(out);
    
    	delete[] pixel_data;
    }
    
    void init(void)
    {
    	/* Setup cube vertex data. */
    	v[0][0] = v[1][0] = v[2][0] = v[3][0] = -1;
    	v[4][0] = v[5][0] = v[6][0] = v[7][0] = 1;
    	v[0][1] = v[1][1] = v[4][1] = v[5][1] = -1;
    	v[2][1] = v[3][1] = v[6][1] = v[7][1] = 1;
    	v[0][2] = v[3][2] = v[4][2] = v[7][2] = 1;
    	v[1][2] = v[2][2] = v[5][2] = v[6][2] = -1;
    
    	/* Enable a single OpenGL light. */
    	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    	glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    	glEnable(GL_LIGHT0);
    	glEnable(GL_LIGHTING);
    
    	/* Use depth buffering for hidden surface elimination. */
    	glEnable(GL_DEPTH_TEST);
    
    	/* Setup the view of the cube. */
    	glMatrixMode(GL_PROJECTION);
    	gluPerspective( /* field of view in degree */ 40.0,
    		/* aspect ratio */ 1.0,
    		/* Z near */ 1.0, /* Z far */ 10.0);
    	glMatrixMode(GL_MODELVIEW);
    	gluLookAt(0.0, 0.0, 5.0,  /* eye is at (0,0,5) */
    		0.0, 0.0, 0.0,      /* center is at (0,0,0) */
    		0.0, 1.0, 0.);      /* up is in positive Y direction */
    
    	  /* Adjust cube position to be asthetic angle. */
    	glTranslatef(0.0, 0.0, -1.0);
    	glRotatef(60, 1.0, 0.0, 0.0);
    	glRotatef(-20, 0.0, 0.0, 1.0);
    }
    
    
    int webBrowserMain()
    {
    	// Window mode MUST include SDL_WINDOW_OPENGL for use with OpenGL.
    	SDL_Window *window = SDL_CreateWindow("Browser", 0, 0, 512, 512, SDL_WINDOW_OPENGL);
    
    	// Create an OpenGL context associated with the window.
    	SDL_GLContext glcontext = SDL_GL_CreateContext(window);
    
    	init();
    
    	while (true)
    	{
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    		drawBox();
    
    		SDL_GL_SwapWindow(window);
    	}
    	SDL_GL_DeleteContext(glcontext);
    
    	return 0; 
    }
    
    DWORD WINAPI MyThreadFunction(LPVOID lpParam)
    {
    	return webBrowserMain();
    }
    
    #define GLUT
    int main(int argc, char *argv[])
    {
    	DWORD threadId = 0;
    	CreateThread(NULL, 0, MyThreadFunction, nullptr, 0, &threadId);
    
    	Window* window = Leadwerks::Window::Create();
    	Context* context = Context::Create(window);
    	World* world = World::Create();
    	Light* light = DirectionalLight::Create();
    	light->SetRotation(35, 35, 0);
    
    	//Create the ground
    	Model* ground = Model::Box(10, 1, 10);
    	ground->SetPosition(0, -0.5, 0);
    	ground->SetColor(0.0, 1.0, 0.0);
    
    	//Create a shape
    	Shape* shape = Shape::Box(0, 0, 0, 0, 0, 0, 10, 1, 10);
    	ground->SetShape(shape);
    	shape->Release();
    
    	//Create a character
    	Pivot* player = Pivot::Create();
    	Entity* visiblecapsule = Model::Cylinder(16, player);
    	visiblecapsule->SetScale(1, 2, 1);
    	visiblecapsule->SetPosition(0, 1, 0);
    	player->SetMass(1);
    	player->SetPhysicsMode(Entity::CharacterPhysics);
    
    	Camera* camera = Camera::Create();
    	camera->SetPosition(Vec3(0, 1.5, 0), false);
    	camera->SetParent(player);
    
    	while (true)
    	{
    		if (window->Closed() || window->KeyDown(Key::Escape)) return false;
    
    		Leadwerks::Time::Update();
    
    		float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S)) * 4;
    		float strafe = (window->KeyDown(Key::D) - window->KeyDown(Key::A)) * 4;
    		player->SetInput(0, move, strafe);
    
    		world->Update();
    		world->Render();
    		context->Sync();
    	}
    }

     

  13. This is the approach I am taking. It doesn't work right now, but it should pass along the idea for #2.


    We would have two threads.

    Thread 1 would be the game in itself.
    Thread 2 would be the HTML render thread that uses OpenGL implementation for Ultralight UI

    Is this a good approach?
     

    const GLchar* vertexShader = R"EOF(
    #version 140
    
    in  vec3 in_Position;
    in  vec3 in_Color;
    out vec3 ex_Color;
    
    void main(void)
    {
    	gl_Position = vec4(in_Position, 1.0);
    	ex_Color = in_Color;
    }
    
    )EOF";
    
    const GLchar* fragShader = R"EOF(
    #version 140
    
    precision highp float; // needed only for version 1.30
    
    in  vec3 ex_Color;
    out vec4 out_Color;
    
    void main(void)
    {
    	out_Color = vec4(ex_Color,1.0);
    }
    
    )EOF";
    
    unsigned int vertexArrayObjID[1];
    unsigned int vertexBufferObjID[2];
    
    void init(void)
    {
    	/* set viewing projection */
    	glMatrixMode(GL_PROJECTION);
    	glFrustum(-0.5F, 0.5F, -0.5F, 0.5F, 1.0F, 3.0F);
    
    	/* position viewer */
    	glMatrixMode(GL_MODELVIEW);
    	glTranslatef(0.0F, 0.0F, -2.0F);
    
    	int vertSize = 9;
    	int colorSize = 9;
    	GLfloat vertData[]{
    		-0.3, 0.5, -1.0,
    		-0.8, -0.5, -1.0,
    		0.2, -0.5, -1.0
    	};
    
    	GLfloat colorData[]{
    		1.0, 0.0, 0.0,
    		0.0, 1.0, 0.0,
    		0.0, 0.0, 1.0
    	};
    
    	// Allocate Vertex Array Objects
    	glGenVertexArrays(1, &vertexArrayObjID[0]);
    	// Setup first Vertex Array Object
    	glBindVertexArray(vertexArrayObjID[0]);
    	glGenBuffers(2, vertexBufferObjID);
    
    	// VBO for vertex data
    	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[0]);
    	glBufferData(GL_ARRAY_BUFFER, vertSize * sizeof(GLfloat), vertData, GL_STATIC_DRAW);
    	glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    	glEnableVertexAttribArray(0);
    
    	// VBO for colour data
    	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjID[1]);
    	glBufferData(GL_ARRAY_BUFFER, colorSize * sizeof(GLfloat), colorData, GL_STATIC_DRAW);
    	glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
    	glEnableVertexAttribArray(1);
    
    	glBindVertexArray(0);
    
    	GLuint renderBuffer[1];
    	glGenRenderbuffersEXT(1, renderBuffer);
    
    	glBindRenderbufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]);
    
    	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGB, 512, 512);
    
    }
    
    void initShaders(void)
    {
    	GLuint glProgram;
    
    	GLuint vertShaderPtr = glCreateShader(GL_VERTEX_SHADER);
    	GLuint fragShaderPtr = glCreateShader(GL_FRAGMENT_SHADER);
    	
    	glShaderSource(vertShaderPtr, 1, &vertexShader, 0);
    	glShaderSource(fragShaderPtr, 1, &fragShader, 0);
    
    	GLint compiled;
    	glCompileShader(vertShaderPtr);
    	glGetShaderiv(vertShaderPtr, GL_COMPILE_STATUS, &compiled);
    	if (!compiled)
    	{
    		cout << "Vertex shader not compiled." << endl;
    	}
    
    	glCompileShader(fragShaderPtr);
    	glGetShaderiv(fragShaderPtr, GL_COMPILE_STATUS, &compiled);
    	if (!compiled)
    	{
    		cout << "Fragment shader not compiled." << endl;
    	}
    
    	glProgram = glCreateProgram();
    
    	glBindAttribLocation(glProgram, 0, "in_Position");
    	glBindAttribLocation(glProgram, 1, "in_Color");
    
    	glAttachShader(glProgram, vertShaderPtr);
    	glAttachShader(glProgram, fragShaderPtr);
    
    	glLinkProgram(glProgram);
    	glUseProgram(glProgram);
    }
    
    void display(void)
    {
    	// clear the screen
    	glClear(GL_COLOR_BUFFER_BIT);
    
    	glBindVertexArray(vertexArrayObjID[0]);	// First VAO
    	glDrawArrays(GL_TRIANGLES, 0, 3);	// draw first object
    
    	glBindVertexArray(0);
    }
    
    void screendump(int W, int H)
    {
    	FILE* out = fopen("screenshot.tga", "wb");
    	char* pixel_data = new char[3 * W*H];
    	short TGAhead[] = { 0, 2, 0, 0, 0, 0, W, H, 24 };
    
    	glReadBuffer(GL_RENDERBUFFER_EXT);
    	glReadPixels(0, 0, W, H, GL_BGR, GL_UNSIGNED_BYTE, pixel_data);
    // TODO: Render to texture instead. Use texture with Context::drawImage
    	fwrite(&TGAhead, sizeof(TGAhead), 1, out);
    	fwrite(pixel_data, 3 * W*H, 1, out);
    	fclose(out);
    
    	delete[] pixel_data;
    }
    
    static Window* window;
    DWORD WINAPI MyThreadFunction(LPVOID lpParam)
    {
    	System::Print("THread2");
    	HDC hdc = CreateCompatibleDC(0);
    
    	HGLRC glrc = wglCreateContext(hdc);
    	wglMakeCurrent(window->hdc, glrc);
    
    	init();
    	initShaders();
    
    	int w = 512;
    	int h = 512;
    	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    	while (true)
    	{
    		display();
    		
    		SwapBuffers(window->hdc);
    		//screendump(w, h);
    	}
    
    	wglDeleteContext(glrc);
    }
    
    
    int main(int argc,const char *argv[])
    {
      // Leadwerks Stuff
      // ...
      // Game Setup
    window = Leadwerks::Window::Create();
    	Context* context = Context::Create(window);
    	World* world = World::Create();
    	Light* light = DirectionalLight::Create();
    	light->SetRotation(35, 35, 0);
    
    	//Create the ground
    	Model* ground = Model::Box(10, 1, 10);
    	ground->SetPosition(0, -0.5, 0);
    	ground->SetColor(0.0, 1.0, 0.0);
    
    	//Create a shape
    	Shape* shape = Shape::Box(0, 0, 0, 0, 0, 0, 10, 1, 10);
    	ground->SetShape(shape);
    	shape->Release();
    
    	//Create a character
    	Pivot* player = Pivot::Create();
    	Entity* visiblecapsule = Model::Cylinder(16, player);
    	visiblecapsule->SetScale(1, 2, 1);
    	visiblecapsule->SetPosition(0, 1, 0);
    	player->SetMass(1);
    	player->SetPhysicsMode(Entity::CharacterPhysics);
    
    	Camera* camera = Camera::Create();
    	camera->SetPosition(Vec3(0, 1.5, 0), false);
    	camera->SetParent(player);
    
    	DWORD threadId;
    	HANDLE thread = CreateThread(NULL, 0, MyThreadFunction, nullptr, 0, &threadId);
    	System::Print("THread1");
    	while (true)
    	{
    		if (window->Closed() || window->KeyDown(Key::Escape)) return false;
    
    		Leadwerks::Time::Update();
    
    		float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S)) * 4;
    		float strafe = (window->KeyDown(Key::D) - window->KeyDown(Key::A)) * 4;
    		player->SetInput(0, move, strafe);
    
    		world->Update();
    		world->Render();
    		context->Sync();
    	}
      

     

  14. I'm trying to implement Ultralight into Leadwerks and I"m struggling to find the best way to do it.

    I can see to "easy" options.

    1. Create a GPUDriver instance for Ultralight which utilizes Leadwerks rendering. (Requires my own custom 2D shader)
    2. Use the OpenGL implementation for Ultralight but use a separate thread for rendering the browser and writing the image data to a shared buffer

    #1 seems very difficult and error prone as I have to provide my own shader and support for this rendering.

    #2 seems easier but I don't know quite the best way to do this.

    Would something like this work for #2?
     

    DWORD WINAPI MyThreadFunction(LPVOID lpParam)
    {
    	System::Print("THread2");
    	HDC hdc = CreateCompatibleDC(0);
    
    	HGLRC glrc = wglCreateContext(hdc);
    	wglMakeCurrent(window->hdc, glrc);
    
    	unsigned char buff[512 * 512 * 3];
    	while (true)
    	{
    		drawUI();
    		
    		dumpToBuffer(512, 512);
    	}
    
    	wglDeleteContext(glrc);
    }

     

    What would you guys recommend?

  15. On 12/27/2018 at 2:52 PM, Josh said:

    Since my Ubuntu install is now bricked I am not going to try it.

    @Josh

    Did you mess up your xorg.config?

    Usually installing graphics drivers causes displays to get lost.

    If you press Ctrl + Alt + F4 this will give you a command line login without GPU.

    If you are still in Utah we can meet up some time so I can try to help you resolve it. Having an Ubuntu version of Leadwerks is important to me. 

  16. @klepto2
    I keep getting an error while linking Leadwerks about adding -fPIE to the compiler. Adding this option doesn't fix the issue.

    I am using CMake for the project itself.

    How well does SWIG work with Leadwerks? Did you compile it off of the Leadwerks.h file, or each individual class such as Window, or Entity?

    Thanks

  17. It would be helpful if we had a PIE version of leadwerks (DLL or .SO file) so that we can make our own DLL files referencing the Leadwerks.so file.

    I am trying to test out SWIG to add python, golang, and Java support. To this, I need to compile my library as a .so file. This can't be done, from my understanding, unless Leadwerks supports Position Independent Execution.

  18. I have been using docker a ton at work, so I decided to try to use it to compile leadwerks C++ projects with.

    I created this GIT repo
    https://github.com/martyj/Leadwerks4.0Docker

    If you move your C++ project into the project folder, and copy your leadwerks steam folder into Leadwerks you can compile a linux build of your game

    You can now compile Linux builds of your game on Windows.

    See "b" and "dr" bash files for how the container is built and ran in Linux, to tweek it for Windows. A simple volume mount change should do the trick.

    Let me know if there is something else you would like to see?

    Me personally, I plan on adding Windows compilation on Linux with this.

    Enjoy!

    • Upvote 1
×
×
  • Create New...