// Copyright (c) 2014 Alex Diener. All rights reserved. #include "glgraphics/GLIncludes.h" #include "glgraphics/VertexTypes.h" #include "watertowerclassic/LevelEditorView.h" #include "watertowerclassic/PhysicsFunctions.h" #include "watertowerclassic/ShellStateGlobals.h" #include #include #include #include #define SUPERCLASS StemObject LevelEditorView * LevelEditorView_create(LevelEditorScreen * levelEditorScreen, ResourceManager * resourceManager) { stemobject_create_implementation(LevelEditorView, init, levelEditorScreen, resourceManager) } bool LevelEditorView_init(LevelEditorView * self, LevelEditorScreen * levelEditorScreen, ResourceManager * resourceManager) { call_super(init, self); self->dispose = LevelEditorView_dispose; self->levelEditorScreen = levelEditorScreen; self->resourceManager = resourceManager; glGenBuffersARB(1, &self->vertexBufferID); glGenBuffersARB(1, &self->indexBufferID); self->spriteTexture = self->resourceManager->referenceResource(self->resourceManager, "texture", "sprites.json"); self->textureAtlas = self->resourceManager->referenceResource(self->resourceManager, "texture_atlas", "sprite_atlas.json"); return true; } void LevelEditorView_dispose(LevelEditorView * self) { glDeleteBuffersARB(1, &self->vertexBufferID); glDeleteBuffersARB(1, &self->indexBufferID); ResourceManager_releaseResource(self->resourceManager, "texture", "sprites.json"); ResourceManager_releaseResource(self->resourceManager, "texture_atlas", "sprite_atlas.json"); call_super(dispose, self); } static const char * spriteNameForBlock(LevelEditorView * self, struct LevelBlock * block) { switch (block->type) { case BLOCK_TYPE_EMPTY: return NULL; case BLOCK_TYPE_STONE: return "stoneblock"; case BLOCK_TYPE_DRY_SOLID: return "blueblock"; case BLOCK_TYPE_WET_SOLID: return "yellowblock"; case BLOCK_TYPE_CRUMBLE: return "crumblingblock"; case BLOCK_TYPE_SWITCHABLE: return "switchableblock"; case BLOCK_TYPE_DEATH: return "deadlyblock"; case BLOCK_TYPE_MOVING: return "movingblock"; case BLOCK_TYPE_FLOATING: return "woodblock"; case BLOCK_TYPE_PHASING: return "phasingblock"; case BLOCK_TYPE_LOCK: return "lockedblock"; case BLOCK_TYPE_LADDER: return "ladder"; case BLOCK_TYPE_LEVER: return "switch"; case BLOCK_TYPE_PUSHABLE: return "boulder"; case BLOCK_TYPE_TRAMPOLINE: return "trampoline"; case BLOCK_TYPE_TELEPORT: return "teleport"; case BLOCK_TYPE_FIRE: return "fireblock"; case BLOCK_TYPE_ICE: return "iceblock"; case BLOCK_TYPE_SAND: return "sandblock"; case BLOCK_TYPE_STICKY: return "stickyblock"; case BLOCK_TYPE_FALLING: return "fallingblock"; default: return "stoneblock"; } } static void getBlockVertices(LevelEditorView * self, struct LevelBlock * block, struct vertex_p2f_t2f_c4f * outVertices, GLushort * outIndexes, unsigned int * ioVertexCount, unsigned int * ioIndexCount) { const char * spriteName; rect4f rect; spriteName = spriteNameForBlock(self, block); if (spriteName == NULL) { return; } rect = getBlockPixelRect(block); GLTextureAtlas_getVerticesWithColor(self->textureAtlas, spriteName, VECTOR2f(roundf(rect.left), roundf(rect.bottom)), VECTOR2f(0.0f, 0.0f), VECTOR2f(rect.right - rect.left, rect.top - rect.bottom), COLOR4f(1.0f, 1.0f, 1.0f, 1.0f), GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } static const char * spriteNameForPowerupType(enum LevelPowerupType type) { switch (type) { case POWERUP_TYPE_HEART: return "heart"; case POWERUP_TYPE_KEY: return "key"; case POWERUP_TYPE_GEM: return "gem"; default: return NULL; } } static void getPowerupVertices(LevelEditorView * self, struct LevelPowerup * powerup, struct vertex_p2f_t2f_c4f * outVertices, GLushort * outIndexes, unsigned int * ioVertexCount, unsigned int * ioIndexCount) { const char * spriteName; rect4f rect; spriteName = spriteNameForPowerupType(powerup->type); if (spriteName == NULL) { return; } rect = getPowerupPixelRect(powerup); return GLTextureAtlas_getVerticesWithColor(self->textureAtlas, spriteName, VECTOR2f(rect.left, rect.bottom), VECTOR2f(0.0f, 0.0f), VECTOR2f(rect.right - rect.left, rect.top - rect.bottom), COLOR4f(1.0f, 1.0f, 1.0f, 1.0f), GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } static void getPlayerVertices(LevelEditorView * self, Vector2i startPosition, struct vertex_p2f_t2f_c4f * outVertices, GLushort * outIndexes, unsigned int * ioVertexCount, unsigned int * ioIndexCount) { GLTextureAtlas_getVerticesWithColor(self->textureAtlas, "player_front", VECTOR2f(startPosition.x * LEVEL_BLOCK_SIZE, startPosition.y * LEVEL_BLOCK_SIZE + LEVEL_BLOCK_SIZE), VECTOR2f(0.0f, 0.0f), VECTOR2f(LEVEL_BLOCK_SIZE, -PLAYER_HEIGHT), COLOR4f(1.0f, 1.0f, 1.0f, 1.0f), GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } static void getLevelVertices(LevelEditorView * self, unsigned int * ioVertexCount, unsigned int * ioIndexCount, GLushort * outIndexes, struct vertex_p2f_t2f_c4f * outVertices) { unsigned int blockIndex, powerupIndex; LevelModel * levelModel; struct LevelBlock * blocks; unsigned int powerupCount; struct LevelPowerup * powerups; levelModel = self->levelEditorScreen->levelSet->levels[self->levelEditorScreen->levelIndex]; if (self->levelEditorScreen->draggingBlocks) { blocks = self->levelEditorScreen->editingBlocks; powerupCount = self->levelEditorScreen->editingPowerupCount; powerups = self->levelEditorScreen->editingPowerups; } else { blocks = levelModel->blocks; powerupCount = levelModel->powerupCount; powerups = levelModel->powerups; } for (blockIndex = 0; blockIndex < LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_COUNT_Y; blockIndex++) { getBlockVertices(self, &blocks[blockIndex], outVertices, outIndexes, ioVertexCount, ioIndexCount); } for (powerupIndex = 0; powerupIndex < powerupCount; powerupIndex++) { getPowerupVertices(self, &powerups[powerupIndex], outVertices, outIndexes, ioVertexCount, ioIndexCount); } getPlayerVertices(self, levelModel->playerStartPosition, outVertices, outIndexes, ioVertexCount, ioIndexCount); if (levelModel->waterLevel > 0) { GLTextureAtlas_getVerticesWithColor(self->textureAtlas, "water", VECTOR2f(0.0f, 480.0f), VECTOR2f(0.0f, 0.0f), VECTOR2f(512.0f, -levelModel->waterLevel), COLOR4f(1.0f, 1.0f, 1.0f, 1.0f), GL_UNSIGNED_SHORT, outVertices, outIndexes, ioVertexCount, ioIndexCount); } } #define BLOCK_HIGHLIGHT_THICKNESS 2 void LevelEditorView_draw(LevelEditorView * self) { struct vertex_p2f_t2f_c4f * vertices; GLushort * indexes; unsigned int vertexCount, indexCount; unsigned int blockIndex; glLoadIdentity(); glOrtho(0.0f, 640.0f, 480.0f, 0.0f, -1.0f, 1.0f); glBegin(GL_QUADS); glColor4ub(0x9D, 0xAB, 0xCC, 0xFF); glVertex2f(0.0f, 480.0f); glVertex2f(0.0f, 0.0f); glColor4ub(0xDE, 0xDF, 0xE0, 0xFF); glVertex2f(256.0f, 0.0f); glVertex2f(256.0f, 480.0f); glVertex2f(256.0f, 480.0f); glVertex2f(256.0f, 0.0f); glColor4ub(0x9D, 0xAB, 0xCC, 0xFF); glVertex2f(512.0f, 0.0f); glVertex2f(512.0f, 480.0f); glEnd(); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glBindBufferARB(GL_ARRAY_BUFFER, self->vertexBufferID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, self->indexBufferID); vertexCount = indexCount = 0; getLevelVertices(self, &vertexCount, &indexCount, NULL, NULL); glBufferDataARB(GL_ARRAY_BUFFER, sizeof(struct vertex_p2f_t2f_c4f) * vertexCount, NULL, GL_STREAM_DRAW); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indexCount, NULL, GL_STREAM_DRAW); vertices = glMapBufferARB(GL_ARRAY_BUFFER, GL_WRITE_ONLY); indexes = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); vertexCount = indexCount = 0; getLevelVertices(self, &vertexCount, &indexCount, indexes, vertices); glUnmapBufferARB(GL_ARRAY_BUFFER); glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER); glVertexPointer(2, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, position)); glTexCoordPointer(2, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, texCoords)); glColorPointer(4, GL_FLOAT, sizeof(struct vertex_p2f_t2f_c4f), (void *) offsetof(struct vertex_p2f_t2f_c4f, color)); self->spriteTexture->activate(self->spriteTexture); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_SHORT, 0); self->spriteTexture->deactivate(self->spriteTexture); glBindBufferARB(GL_ARRAY_BUFFER, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_COLOR_ARRAY); for (blockIndex = 0; blockIndex < LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_COUNT_Y; blockIndex++) { if (self->levelEditorScreen->inspectorView->block == &self->levelEditorScreen->levelSet->levels[self->levelEditorScreen->levelIndex]->blocks[blockIndex]) { rect4f blockRect; blockRect.left = blockIndex % LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_SIZE; blockRect.top = blockIndex / LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_SIZE; blockRect.right = blockRect.left + LEVEL_BLOCK_SIZE; blockRect.bottom = blockRect.top + LEVEL_BLOCK_SIZE; glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glBegin(GL_QUADS); glVertex2f(blockRect.left - BLOCK_HIGHLIGHT_THICKNESS, blockRect.top - BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.left, blockRect.top); glVertex2f(blockRect.right, blockRect.top); glVertex2f(blockRect.right + BLOCK_HIGHLIGHT_THICKNESS, blockRect.top - BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.left - BLOCK_HIGHLIGHT_THICKNESS, blockRect.top - BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.left - BLOCK_HIGHLIGHT_THICKNESS, blockRect.bottom + BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.left, blockRect.bottom); glVertex2f(blockRect.left, blockRect.top); glVertex2f(blockRect.right, blockRect.top); glVertex2f(blockRect.right, blockRect.bottom); glVertex2f(blockRect.right + BLOCK_HIGHLIGHT_THICKNESS, blockRect.bottom + BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.right + BLOCK_HIGHLIGHT_THICKNESS, blockRect.top - BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.left, blockRect.bottom); glVertex2f(blockRect.left - BLOCK_HIGHLIGHT_THICKNESS, blockRect.bottom + BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.right + BLOCK_HIGHLIGHT_THICKNESS, blockRect.bottom + BLOCK_HIGHLIGHT_THICKNESS); glVertex2f(blockRect.right, blockRect.bottom); glEnd(); break; } } glDisable(GL_BLEND); }